How do I check if it returns a null? - ruby-on-rails

i should check whether there is some values based on this condition. if there is some, then i should do one action or else do a different action.
i work on rails, mysql and xp
this is not working #test.nil? suggest me a alternate way
#test=Model.find(:all,:conditions=>"id=#someid")thanks in advance

#test.nil? should work fine. It's probably not working because your find method is wrong. Try this instead:
#test = Model.find_by_id(#someid)
An alternative syntax is:
#test = Mode.find(#someid)
—Which will raise a RecordNotFound exception if the record doesn't exist.

Related

Switch off Capybara::ElementNotFound / avoid nested rescue

I've got an issue with a method shared across a wide number of integration tests.
The problem is, I need to find one of two buttons, and have so far only come up with the following unwieldy syntax for avoiding Capybara's ElementNotFound error:
new_button = begin
find(".button_one")
rescue Capybara::ElementNotFound
begin
find('.button_two')
rescue Capybara::ElementNotFound
raise Capybara::ElementNotFound, "Missing Button"
end
end
new_button.click
This works as expected: if the first button's not found, the second one is, and they're clicked. If neither are present, the error is raised.
Despite this, I really don't like the nested rescues and would like to tidy this up.
The simplest solution which feels like it should exist, though I've not found this anywhere: does anyone know if there's an option to return nil in Capybara's find method, rather than raising the exception?
For example, the following pseudocode...
new_button = find('.button_one', allow_nil: true) || find('.button_two', allow_nil: true)
new_button ? new_button.click : raise(Capybara::ElementNotFound, "Missing Button")
...would be perfect.
Otherwise, any suggestion of how best to rescue the two errors and avoid the horrible nested rescue?
Footnote: this code exists within a large existing structure, which previously worked fine where it shouldn't have. Fixing another issue has caused this problem, which is used widely throughout the suite. I'd love to adjust the calls and use the correct elements (and so avoid this altogether), though that's going to be a big project a little later in the day.
If only one of the buttons is ever on the page, the simplest solution is to just look for both buttons at once using the CSS comma
find(".button_one, .button_two").click
If it's possible for both buttons to be on the page at the same time then that will get you an Ambiguous match error, in which case you could do something like
find(".button_one, .button_two", match: :first).click
or
all(".button_one, .button_two")[0].click
It's also possible to check whether an element exists without raising an exception using the Capybara provided predicates has_css?/has_xpath?/etc. which would give code like
if page.has_css?(".button_one")
find(".button_one")
else
find(".button_two")
end.click
but in this case using the CSS comma would definitely be the better solution.
Try with the x-path //button[contains(#class,'button_one') or contains(#class, 'button_two'] as given below,
new_button = begin
find(:xpath, "//button[contains(#class,'button_one') or contains(#class, 'button_two']")
rescue Capybara::ElementNotFound
raise Capybara::ElementNotFound, "Missing Button"
end
new_button.click
I'm not familiar with Ruby, so I'll leave the link to Ruby docu and Capybara docu. The idea is to use find_elements instead of find_element. Why? find_elements won't throw any exception if there is no elements found. The pseudo code would be like this:
new_button = find_elements('.button_one').size() > 0 ? find('.button_one') || find('.button_two')
And you don't need to handle with exceptions anymore.

.where returns nil exception if user does not enter anything rails 4

I want to query some data from table based on user for submission.
Its working fine but if I post nothing in the the fields and post my form, it returns me nil exception.
Is there a way we can deal with nil exception, or do I need to change query?
question_options = question.question_options.where(id: self.option_id).first
The simplest solution is to use try. For example:
question_options = question.question_options.where(id: self.option_id).try(:first)
The documentation for try is here
For your issue multiple solutions exists. Your query returns nil and thats ok because nothing was found. The simplest solution is an if statement. if question_options.nil? do some thing else. Or you can use an unitialized object (or a NullObject) do work with it question_option = question.question_options.where(id: self.option_id).first || QuestionOption.new
The are other possibilites too. It depends on your requirement what way you choose.

Rails create method not adding record to the table, but works for the IRB

I've looked everywhere for a similar error but couldn't find a solution, so in desperation I'm posting here.
My controller has this:
def add_upc
#upcs = Dvd.add_upc(params[:dogTag], params[:newUpc])
end
and in the Model we have:
def self.add_upc(dogTag, newUpc)
existingUpc = Dvd.find(dogTag).dvd_upc2title.find_by_upc(newUpc)
if existingUpc.nil?
createdUpc = Dvd.find(dogTag).dvd_upc2title.create(:upc => newUpc)
if createdUpc
upcs = createdUpc
else
upcs = 'Error: nothing was created'
end
end
end
I've set up a view page to see what's happening and I can see the object being created by createdUpc. I can also confirm that the parameters dogTag and newUpc are being passed correctly. Yet the record is not being added to the table.
Weirdly, this does work if I issue the Dvd.find(dogTag).dvd_upc2title.create(:upc => newUpc) command with the values substituted for the variables from the IRB.
Can't figure out why this is not working. I'm new to Rails so don't know what other error debugging I could use to figure out where the problem lies.
Ideas are welcome.
Thanks.
Edit:
Found the error thanks to RyanWilcox, it was the validation I had set up in the controller for UPC telling me that value already existed (even though UPCs are supposed to be unique. Is there a way to validate on a combination of 2 fields?
What I really like doing for situations like this ("why did this fail to save?") is using create! instead of create.
This will throw an exception on error, with the failed validation's text as the message of the exception. It makes problems like this obvious.

Rails 2: Model.find(1) gives ActiveRecord error when id 1 does not exist

I am using Rails 2.3.5 and in that if I give Model.find(1) and if 1 is not in the database, it returns ActiveRecord error. Should it just be returning nil as in the case of Model.find_by_column('..')?
This is the expected behavior. I think David explains this the best himself, so here is a quote from Ruby, S., Thomas, D. & Hansson, D.H., 2009. Agile Web Development with Rails, Third Edition Third Edition., Pragmatic Bookshelf (p.330).
When you use a finder driven by
primary keys, you’re looking for a
particular record. You expect it to
exist. A call to Person.find(5) is
based on our knowledge of the people
table. We want the row with an id of
5. If this call is unsuccessful—if the record with the id of 5 has been
destroyed—we’re in an exceptional
situation. This mandates the raising
of an exception, so Rails raises
RecordNotFound.
On the other hand,
finders that use criteria to search
are looking for a match. So,
Person.find(:first,
:conditions=>"name=’Dave’") is the
equivalent of telling the database (as
a black box) “Give me the first person
row that has the name Dave.” This
exhibits a distinctly different
approach to retrieval; we’re not certain up front that we’ll get a result.
It’s entirely possible the result set
may be empty. Thus, returning nil in
the case of finders that search for
one row and an empty array for finders
that search for many rows is the
natural, nonexceptional response.
If you really don't want the exception, you can use find_by_id:
# #user = User.find(params[:id]) # original code
#user = User.find_by_id(params[:id])
if #user
# found!
else
# not found
end
This should be faster than a separate exists? check.
EDIT: Note that as #Miguelgraz commented, in Rails 4 you should instead say User.find_by(id: params[:id]). Same functionality, but now the implementation won't need method_missing.
throwing the exception is the expected behavior.
in fact in the normal course of events if you let the exception go unhandled your rails server will return the proper 404 page not found error.
if you'd like for it to return nil you can catch it yourself:
begin
#model = Model.find(id_provided)
rescue ActiveRecord::RecordNotFound => e
#model = nil
end
If you want the exception to be thrown in find_by_attributes flavors of the finder methods, you can use the bang! version of the method.
For example,
Model.find_by_category!(a_category_value)
will throw RecordNotFound if no match is found.
I found this to be DRY in scenarios like RESTful controllers, where I have a common error handler for the exception and I want my actions to behave consistently when a resource matching the given parameters is not found.
You can check if the record exists before fetching it.
#model = Model.find(id) if Model.exists?(id)
Rails 4 Method
if user = User.find_by(id: params[:id])
#do something with user
else
#throw error or redirect
raise ActiveRecord::RecordNotFound
end
You can use find_by with the required attribute (in your case the id) this will return nil instead of giving an error if the given id is not found.
Model.find_by_id(id_value)
You could also use where but you have to know that where return an active record relation with zero or more records you need to use first to return only one record or nil in case zero records return.
Model.where(id: id_value).first
You can simply use:
user = User.find(10) rescue nil

In Ruby on Rails, is there a way to say, try Product.find(12345) but don't error if not found?

For example, just have it return nil if not found,
or must we always use begin... rescue... end to catch the exception?
You can use
Product.find_by_id(12345)
. This would return nil and not error.
Thanks....
You can use rescue_from to specify a method to use to handle the exception. If it's something that's used in multiple places this will help remove duplication. You could even put it in your application controller if it's used across controllers. Here are some examples: http://m.onkey.org/rescue-from-dispatching
You could test it first with Product.exists?(12345)

Resources