How can I set a variable to a value, only if that value is valid? - ruby-on-rails

I want to set a variable to a given value, but only if the value is valid.
Right now this is the code I have:
if Something.find(params[:id].comments.first.exists?
#comment = Something.find(params[:id]).comments.first
else
#comment = nil
end
But this is inefficient because it has to load the records twice.
I tried to use the ruby method try to ensure that the variable would only be set if the value is valid:
#comment = Something.try.find(params[:id]).comments.first
but no matter where I put it, I get back a "nil is not a symbol" error. It seems try is only for printing variables.
Anyone know how else I can accomplish this with only one query?

You could try:
#comment = Comment.find_by(something_id: params[:id])

Did you tried?
if #comment = Something.find(params[:id]).comments.first
# do something with your #comment variable
else
# do something else
end
More examples: Check if record exists from controller in Rails

# Attempt your query
#comment = Something.find(params[:id]).comments.first
# If the record does not exist, use rescue to handle the exception gracefully
rescue ActiveRecord::RecordNotFound
# Handle the exception
#comment = nil
end
You can find more information on exceptions and exception handling here.

I think this is what you want:
#comment = Something.find_by(id: params[:id]).try(:comments).try(:first)
In this case find_by will return a Something object or nil. In case of nil, the chain of tries will still return nil, and, in case of object, methods in tries will be executed and give you the first comment, if such exists (note! you might still get a nil if object exists because that object might not have any comments).
Thus, you will set your #comment only if Something object exists and it has comments; otherwise, it will be nil.

Related

why no implicit conversion of nil into Hash?

after setup a search into a serializer!
Rails spits out
no implicit conversion of nil into Hash
So, please someone can point out whats wrong with this code?
class SearchController < ApplicationController
def results
results_query = PgSearch.multisearch(params[:q]).paginate(page: page, per_page: 20)
result = results_query.map(&:searchable).map do |result_item|
case result_item.class.name
when 'Post'
PostSerializer.new(result_item)
else
raise NotImplementedError
end
end
render json: {
items: result,
page: page,
pages: results_query.total_pages
}
end
def page
params[:page] || 1
end
def serialize(data, serializer)
ActiveModel::Serializer::CollectionSerializer.new(data, each_serializer: serializer)
end
end
Since your case statement isn't checking many values, you could always make it into a standard if/else statement:
if result_item && result.class.name == 'Post'
PostSerializer.new(result_item)
else
raise NotImplementedError
end
Well, on the screenshots you've provided we can see the log message specifies that the error is on line 5.
According to your code, line 5 is: case result_item.class.name
The error message is TypeError (no implicit conversion of nil into Hash).
You're trying to get the class then the name of result_item. So the problem is with result_item which is equal to nil.
In order the resolve your problem you might want to check the ouput of results_query.map(&:searchable).map.
Based on the screenshot you've provided, I've quickly checked the source code. The offending line seems to be this one: https://github.com/Casecommons/pg_search/blob/master/lib/pg_search/document.rb#L22. The only reason why this would raise the described TypeError is if PgSearch.multisearch_options is nil – which, as far as I understand the code, would only be possible if you accidentally overwrote it in a wrong way. So I'd suggest doublechecking your global setup for PgSearch.multisearch_options to make sure this is actually set.
The east way to check the setting is by using a debugger or putting something like puts PgSearch.multisearch_options or Rails.logger.info 'PgSearch.multisearch_options' into the controller directly above the call that's failing.

Ruby on Rails beginner question : equality

I'm starting to know ROR and I was doing a kind of blog with articles, etc...
I did this code :
def show
id = params[:id]
list = Article.all
is_valid = false
list.all.each do |article|
if article.id == id
#is_valid = true
break
end
end
As you can see, this code just wants to check if the article ID exists or not. So I'm testing equality between id and article.id (which's a model linked to the appropriated table in the database) BUT when I try to use or display #is_valid boolean I saw that article.id == id is FALSE every time, even if article.id = 2 and id = 2. I tried to think about everything that can make this occuring, but I admit I still misunderstand this.
Then I ask you if you know why this is occuring. Of course, an equality like 2 == 2 will change #is_valid to true.
Thank you for your help !
Maybe its because params[:id] it's a string and article.id it's an Integer
(byebug) params
{"controller"=>"admin/my_controller", "action"=>"edit", "id"=>"1"}
And yes it is... "id" is a string "1", so you may try this:
def show
id = params[:id].to_i
list = Article.all
is_valid = false
list.all.each do |article|
if article.id == id
#is_valid = true
break
end
end
end
And maybe could work.
This is the answer to your question,
But if you want to learn a little more about Activerecord you can do this
Article.exists?(params[:id])
and that will do what you are trying to do just with a query against db.
and if you want to get just a simple article
record = Article.find_by(id: params[:id]) #return nil when not exist
if record # if nil will threat like false on ruby
#my code when exist
else
#my code when not exist
end
will work (you also can use find but find will throw an exception ActiveRecord::RecordNotFound when not exists so you have to catch that exception.
Activerecord has many ways to check this you dont need to do it by hand.
def show
#article = Article.find(params[:id])
end
This will create a database query which returns a single row. .find raises a ActiveRecord::NotFound exception if the record is not found. Rails catches this error and shows a 404 page. Article.find_by(id: params[:id]) is the "safe" alternative that does not raise.
Your code is problematic since list = Article.all will load all the records out of the database which is slow and will exhaust the memory on the server if you have enough articles. Its the least effective way possible to solve the task.
If you want to just test for existence use .exists? or .any?. This creates a COUNT query instead of selecting the rows.
Article.where(title: 'Hello World').exists?

Could not find record error while deleting record in Rails

I'm trying to delete a record by passing id of that record. The code looks like this:
def destroy_catalogue_entry
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
if #catalogue_entry.destroy
flash[:success] = 'Catalogue entry deleted successfully.'
else
flash[:error] = 'Failed...'
end
end
I'm getting an interesting error. When my function destroy_catalogue_entry is called it shows:
Couldn't find CatalogueEntry with 'id'=16
but as I comment If condition section and render #catalogue_entry as json, the output is printed successfully. So how is it possible? Am I making some silly mistake or is there logical reason. Please enlighten me.
Solved! All I did is this:
def destroy_catalogue_entry
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
if #catalogue_entry.destroy
flash[:success] = 'Catalogue entry deleted Successfully'
redirect_to action: :view_catalogue_entries, dc_id: #catalogue_entry.dc_id
else
flash[:success] = 'Failed...'
end
end
When I notice the console, the record was getting deleted successfully but after that there was a SELECT query for the same record, that is why it was throwing the error Couldn't find CatalogueEntry with 'id'=16. As I redirected it, the problem was solved.
I think destroy method is returning an object. In ruby anything other than false or null will be taken to true in if statement. You can do puts on destroy method and see what its returning.
i presume your,
#catalogue_entry = CatalogueEntry.find(params[:catalogue_entry_id])
is returning that error because it cant find CatalogueEntry with id 6, make sure you have CatalogueEntry with that id.

What is returned by calling 'where'?

I have following question, let
#post=Post.where(title: "title1")
what should be #post if "title1" exists or not? How can I check if 'where' returned any element?
In my application I just called
if(#post) .... else .... end
but it always get into else
Try:
#post=Post.where(title: "title1").first
Then #post would be either a Post object with title = "title1" or nil.
.where returns a ActiveRecord_Relation object, which is the result of filtering the current relation according to the conditions in the arguments.
An alternative is to use find_by as suggested by #D-side in the comments:
#post = Post.find_by(title: "title1")

Unable to copy Ruby object's attributes

I have a very painful issue here, if some one could help ?
I have a class Task with attributes and I wanted to make a bang method (because I'm changing the receiver) but I'm not able to change object attributes properly :
def reject!
return nil if self.previous_owner.nil?
self.delegate = false
# Before, owner equal a User object
self.owner = self.previous_owner # previous_owner is also a User object, but different
self.previous_owner = nil
return self if self.save
raise "Can't save object"
end
This won't work because self.owner will be nil...
I know this is because telling Ruby that self.owner = self.previous_owner and then changing self.previous_owner to nil.
So how can I avoid this ? I tried clone and dup method, but I'm not sure I want to have a new copied User object...
Strange thing too, if I try this in rails console :
a = 'Foo'
b = a
a = 'New value'
puts a # "New value"
puts b # "Foo"
So I think I'm missing something...
Please note that self.owner and self.previous_owner are convenience methods provided by Rails. The actual fields should be called something like owner_id and previous_owner_id and contain the actual id of the User you want to link to.
So a simpler, and failsafe approach is to write
self.owner_id = self.previous_owner_id
self.previous_owner = nil # this will unlink the previous owner
self.save!
and self.save! will raise if the save fails.

Resources