Better Rails code for update or create clause? - ruby-on-rails

The code smells and i'm sure i'm missing a helper to do a simple
update or create query like the below snippet :
#user_answer = current_user.user_answers.find_by_question_id(params[:a_question])
if #user_answer.nil?
#user_answer = current_user.user_answers.build({ :answer_id => params[:an_answer] , :question_id => params[:a_question] })
#user_answer.save
else
#user_answer.update_attributes(:answer_id => params[:an_answer])
#user_answer.save
end

You might be looking for the find_or_initialize_by method. For example:
#user_answer = current_user.user_answers.find_or_initialize_by_question_id(params[:a_question])
#user_answer.answer_id = params[:an_answer]
#user_answer.save

How about,
#user_answer = current_user.user_answers.find_or_create_by_question_id(params[:a_question])
This will avoid the explicit save

Related

better way to build association in controller

I need a link in a show method of a parent class for creating associated models, so I have the code:
link_to "incomplete", new_polymorphic_path(part_c.underscore, :survey_id => survey.id)
in a helper.
This links to a part, which has new code like this:
# GET /source_control_parts/new
def new
get_collections
if params[:survey_id]
#s = Survey.find(params[:survey_id])
if #s.blank?
#source_control_part = SourceControlPart.new
else
#source_control_part = #s.create_source_control_part
end
else
#source_control_part = SourceControlPart.new
end
end
I know this is not very DRY. How can I simplify this? Is there a RAILS way?
How about this:
def new
get_collections
get_source_control_part
end
private
def get_source_control_part
survey = params[:survey_id].blank? ? nil : Survey.find(params[:survey_id])
#source_control_part = survey ? survey.create_source_control_part : SourceControlPart.new
end

How to refactor complicated logic in create_unique method?

I would like to simplify this complicated logic for creating unique Track object.
def self.create_unique(p)
f = Track.find :first, :conditions => ['user_id = ? AND target_id = ? AND target_type = ?', p[:user_id], p[:target_id], p[:target_type]]
x = ((p[:target_type] == 'User') and (p[:user_id] == p[:target_id]))
Track.create(p) if (!f and !x)
end
Here's a rewrite of with a few simple extract methods:
def self.create_unique(attributes)
return if exists_for_user_and_target?(attributes)
return if user_is_target?(attributes)
create(attributes)
end
def self.exists_for_user_and_target?(attributes)
exists?(attributes.slice(:user_id, :target_id, :target_type))
end
def self.user_is_target?(attributes)
attributes[:target_type] == 'User' && attributes[:user_id] == attributes[:target_id]
end
This rewrite shows my preference for small, descriptive methods to help explain intent. I also like using guard clauses in cases like create_unique; the happy path is revealed in the last line (create(attributes)), but the guards clearly describe exceptional cases. I believe my use of exists? in exists_for_user_and_target? could be a good replacement for find :first, though it assumes Rails 3.
You could also consider using uniqueness active model validation instead.
##keys = [:user_id, :target_id, :target_type]
def self.create_unique(p)
return if Track.find :first, :conditions => [
##keys.map{|k| "#{k} = ?"}.join(" and "),
*##keys.map{|k| p[k]}
]
return if p[##keys[0]] == p[##keys[1]]
return if p[##keys[2]] == "User"
Track.create(p)
end

Ruby: compare hash to hash value trouble

I have such part of "ghost look like" code (but it so must be, as db is huge and have many tables):
def search_group
#search_trees = SearchTree.all
#designation = Designation.find(:all, :conditions => { :DES_ID => #search_trees.map(&:STR_DES_ID)})
#text = DesText.find(:all, :conditions => { :TEX_ID => #designation.map(&:DES_TEX_ID)})
#search_result = #text.find_all{|item| item.TEX_TEXT.include?(params[:search_group_text])}
#designation_back = #designation.find_all{|item| item.DES_TEX_ID == #search_result.TEX_ID}
#search_trees_back = #search_trees.find_all{|item| item.STR_DES_ID == #designation_back.DES_ID}
respond_to do |format|
format.html
end
end
I try to compare
#designation_back = #designation.find_all{|item| item.DES_TEX_ID == #search_result.TEX_ID}
but i get errors, something bad...undefined method `TEX_ID'. As i think, it's via i compare hash and hash in bad way... How can i do this?
#search_result = #text.find_all{|item| item.TEX_TEXT.include?(params[:search_group_text])}
#designation_back = #designation.find_all{|item| item.DES_TEX_ID == #search_result.TEX_ID}
it's because #search_result is an array and not an object where you can call that method on.
#search_results is an array. If you know it is returning just one result, you can do #search_results[0].Tex_Id, otherwise have to loop through for each value of #search_results.
try 'pry' gem to debug what results you are getting from each assignment.

In ActiveRecord, how to check if an object property is nil?

Suppose I need to check if a certain property is not set.
I imagine something like this but It doesn't work.
#users = User.find_all_by_role(["role = ?",nil])
I tried some other variants with no luck.
I guess this should be pretty straightforward.
Thank you!
Using ActiveRecord's pre-3.0 syntax:
#users = User.find(:all, :conditions => { :role => nil })
After 3.0 you can write:
#users = User.where(:role => nil)
Try: #users = User.find(:all, :conditions=>'role is null')
#users = User.where(:roles => nil).all
There's no need to break into SQL for this.

How to have condition in ActiveRecord update

I am trying to update a record. Am using the following code.
Proddiscount.update({:prodid => params[:id]}, {:discount=>params[:discount]})
Query Im trying to have is:
update proddiscount set discount = '' where prodid = ''
If prodif is not a primary key, use update_all (read more here)
Proddiscount.update_all("discount = #{params[:discount]}", ["prodid = ?", params[:prodid])
But it won't trigger validations.
How about doing this:
#prod = Proddiscount.find(:first, :conditions => {prodid => params[:id]})
#prod.update_attributes({:discount=>params[:discount]})

Resources