MYSQL Search on Rails - mysql

Suppose that I do not have a certain id in mysql database. I am using rails, so the following code that I am using to query the database is the following...
#customer = Customer.find(params[:id])
How do I raise an exception of the ID does not exist? Please let me know :)
Thank you in advance!

When you call find on an ActiveRecord model it will automatically raise an ActiveRecord::RecordNotFound exception if the ID passed doesn't correspond to an existing record in the database. You can recover from this, but make sure you don't rely on this as expected flow (i.e. you don't want to do the above routine in a check on every page load, even when you don't know if params[:id] is even set).
def show
#customer = Customer.find params[:id]
rescue ActiveRecord::RecordNotFound
redirect_to customers_path
end

If the id does not exist your #customer will be nil.
raise Exception.new "SomeText" if #customer.nil?

Related

Is there a specific ordering needed for classes in Peewee models?

I'm currently trying to create an ORM model in Peewee for an application. However, I seem to be running into an issue when querying a specific model. After some debugging, I found out that it is whatever below a specific model, it's failing.
I've moved around models (with the given ForeignKeys still being in check), and for some odd reason, it's only what is below a specific class (User).
def get_user(user_id):
user = User.select().where(User.id==user_id).get()
return user
class BaseModel(pw.Model):
"""A base model that will use our MySQL database"""
class Meta:
database = db
class User(BaseModel):
id = pw.AutoField()
steam_id = pw.CharField(max_length=40, unique=True)
name = pw.CharField(max_length=40)
admin = pw.BooleanField(default=False)
super_admin = pw.BooleanField()
#...
I expected to be able to query Season like every other model. However, this the peewee error I run into, when I try querying the User.id of 1 (i.e. User.select().where(User.id==1).get() or get_user(1)), I get an error returned with the value not even being inputted.
UserDoesNotExist: <Model: User> instance matching query does not exist:
SQL: SELECT `t1`.`id`, `t1`.`steam_id`, `t1`.`name`, `t1`.`admin`, `t1`.`super_admin` FROM `user` AS `t1` WHERE %s LIMIT %s OFFSET %s
Params: [False, 1, 0]
Does anyone have a clue as to why I'm getting this error?
Read the error message. It is telling you that the user with the given ID does not exist.
Peewee raises an exception if the call to .get() does not match any rows. If you want "get or None if not found" you can do a couple things. Wrap the call to .get() with a try / except, or use get_or_none().
http://docs.peewee-orm.com/en/latest/peewee/api.html#Model.get_or_none
Well I think I figured it out here. Instead of querying directly for the server ID, I just did a User.get(1) as that seems to do the trick. More reading shows there's a get by id as well.

Ruby `unless` not working

I am learning Ruby at the moment and I have written the below code, however it is causing errors when running.
The idea is that a channel will only be inserted in to the database if it is not already present in the database (checked via exists? method).
def exists?(channel)
rs = #con.query("SELECT * FROM channels WHERE name = #{channel}")
return true unless rs.empty?
end
channels.each do |channel|
#con.query("INSERT INTO channels (name, timestamp) VALUES ('#{channel}', '#{Time.now.to_i}')") unless channel.exists?
Here is an error message shown once I include this code:
undefined method `exists?' for "#channel1":String
Is there an error in the code that I've written?
I think you're confused about the syntax. If you want to use your above-defined method, you should have this:
#con.query("INSERT INTO channels (name, timestamp) VALUES ('#{channel}', '#{Time.now.to_i}')") unless exists?(channel)

Rspec and Capybara: saving results to database?

I'm fairly new to RSpec and have been trying to create some tests for my website, on which a user can post a reservation to the website, which is then saved to our database. I've been trying, using Rspec and Capybara, to simulate a user posting a reservation to the website. We have an existing test database, and at the end of the Rspec test want the new reservation to be written to the database, and not removed at the end of the Rspec test.
One of two things happens when we run the code: either it "works" but the new reservation can't be found in the database, or we get this error:
Failure/Error: Unable to find matching line from backtrace
ActiveRecord::StatementInvalid:
Mysql2::Error: This connection is in use by: #<Thread:0x007fb421fd6218 sleep>: SELECT `users`.* FROM `users` WHERE `users`.`id` = 6 ORDER BY `users`.`id` ASC LIMIT 1
# ./app/controllers/application_controller.rb:95:in `pass_login_status_to_js'
# ./app/middleware/search_suggestions.rb:12:in `call'
Why would this be happening? I realize that Capybara isn't generally meant to be making permanent changes to a database; is there a different program/gem you recommend?
I currently have config.use_transactional_fixtures = false, and also have added the following on the recommendation of a few websites:
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
To reiterate, I do want Capybara to be writing to my database (we use SQL). What can I do differently? Does it have something to do with database cleaner?
Yes, it has everything to do with database_cleaner. If you have it setup properly, it will clean your database between scenarios, to keep the tests isolated.
There are a few ways to do what you want:
You can explicitly tell database_cleaner not to clean certain tables between scenarios:
DatabaseCleaner.strategy = :transaction, {except: [:countries, :states]}
DatabaseCleaner.clean_with(:truncation, {except: [:countries, :states]})
You can add your code to a before(:each) or before(:all) block
You can add your data to one or many fixtures
There are only a few cases where you should share data between scenarios (ie. countries, states tables, which are good candidates for #3)
In any other case, I advise against sharing data between scenarios.

Check row exist or not in Ruby on Rails

I am new to Ruby on Rails and I have basic knowledge of mysql. I am using MySQL db. My question is -- how to check if a row is exists or not in a table. I have tried this code but it's not going straight to the else block, not the if block:
#tasks = User.find_by("user_name = ? AND password = ?", params[:user_name], params[:password])
if #tasks
redirect_to action: 'index', status: 302
else
redirect_to action: 'detail', status: 302
end
If you want to find if a user with the given name and password exists using Ruby on Rails, then you can do this:
User.where(user_name: params[:user_name], password: params[:password]).exists?
See the RailsGuides: Existence of Objects.
The Cause of the Original Problem?
So this it the code that the original poster originally submitted:
User.find_by("user_name = ? AND password = ?", "#{params[:user_name]}", "#{params[:password]}")
I removed the string interpolation because it was unnecessary
User.find_by("user_name = ? AND password = ?", params[:user_name], params[:password])
and apparently that fixed the problem. I'm not sure why it would make a difference though, the interpolated string should be the same value as the values in the params dictionary.
You can use any of these solutions depending on your requirement.
Sol-1:
User.where(user_name: params[:user_name], password: params[:password]).exists?
Sol-2:
User.find_by_user_name_and_password(params[:user_name], params[:password])
where returns an ActiveRecord::Relation (not an array, even though it behaves much like one), which is a collection of model objects. If nothing matches the conditions, it simply returns an empty relation.
find (and its related dynamic find_by_columnname methods) returns a single model object, or possibly a collection of model objects in an Array (not a Relation). If nothing is found, an ActiveRecord::RecordNotFound exception is raised.
So yes, if you only want and expect a single object, using find is easier, as otherwise you must call Model.where.first.
you can try it as well..
User.find_by_user_name_and_password(params[:user_name], params[:password])

Rails - Model Validations doesn't apply on mysql insert/update command

For the reason, I've used mysql cmd insert into table_name (....) update custom_reports ...and hence I miss out on Model validations
validates_uniqueness_of :name
validates_presence_of :name, :description
How to validate now in rails way? Or, use the mysql way to validate(needs help in this way too)?
Rails validation and other ActiveRecord and ActiveModel magic don't work if you only execute custom SQL command. None of your model classes is even instantized then.
For Mysql (or any sql like DB), you can modify the column attribute to:
Unique (this would validate uniqueness)
Not null (this would validate presence)
I know doing the above with OCI8 and oracle would result in exceptions which I am guessing should be same with ActiveRecord and Mysql, so you should be handling your exceptions correctly
But as #Marek as said you should be relying on Active record and be doing things like
Model.create()
OR
model_instance.save()
If you want to find (and perhaps handle) the entries in your db that are not valid, try the following in the rails console:
ModelName.find_each do |item|
unless item.valid?
puts "Item ##{item.id} is invalid"
# code to fix the problem...
end
end
valid? runs the Validations again, but does not alter the data.