Rails Activerecord: Update where conditions... else create - ruby-on-rails

I need to check multiple columns of a table to see if I find a match. If I find a match I need to "updateattributes" of the matching record with all of my form params... Else I need to add a new record with all of my form params.
if #somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2])
if #somethingtoupdate = Model.update_attributes(params[:something])
redirect_to somewhere_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
#added = Model.new(params[:something])
if #added.save
redirect_to somewhere_path, :notice => "The new record was created"
else
render "myformlocation"
end
end
Update
#somethingtoupdate = Model.where("this_id = ? and that_id = ?", params[:something][:this_id], params[:something][:that_id])
if ! #somethingtoupdate.empty?
if #somethingtoupdate.update_attributes(params[:something])
redirect_to some_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
#added = Model.new(params[:something])
if #added.save
redirect_to some_path, :notice => "The new record was created"
else
render "myformlocation"
end
end
This is where I stand now thanks to #micahbf.
But, I am still getting an error on my "update_attributes" when there is a matching record.
Seems like this should work.... What am I missing or doing wrong?

This is because where does not return nil if it doesn't find anything, it returns an empty array, which is still truthy, so the block gets executed.
You can use empty? to check whether to run the block or not.
Note also that if it finds a match, the match will still be returned inside of an array (even if there was only one match). So you will have to do something like call first on the result to take the first returned model and update it.
So, the top might look like:
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2])
if ! #somethingtoupdate.empty?
if #somethingtoupdate.first.update_attributes(params[:something])
redirect_to some_path, :notice => "The existing record was updated"
else
render "myformlocation"
end
else
// do stuff if the query found no matches
end

I think here is short method to find record and if found then update record and if record not found then create it.
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2]).first_or_initialize
#somethingtoupdate.update_attributes(params[:something])

First of all, Model.update_attributes(params[:something]) is not working (at least in Rails 3.2.12). It should be #somethingtoupdate.update_attributes(params[:something]).
Also, there is an existing method for this kind of purpose: first_or_create.
#somethingtoupdate = Model.where("column1 = ? and column2 = ?", params[:something][:column1], params[:something][:column2]).first_or_create

Related

RoR Active record 'where' doesn't work properly

This is my code, the first part is the problem, and the second is perfectly working.
def show
if #user.cooker?
#pushs = #user.pushs.where(taked_by = #user.id)
else
#pushs = #user.pushs
end
end
Well the code say, if I'm a cooker, I want to display all the push where the variable :taked_by is has the same id than my user.id
And the second par say that if I'm not a cooker, display all my own push.
Do taked_by: #user.id or :taked_by => #user.id
def show
if #user.cooker?
#pushs = #user.pushs.where(taked_by: #user.id)
else
#pushs = #user.pushs
end
end
Let me know if it worked.

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.

Take random ids, then store those random ids into the db

so I'm working on a code snippet that essentially takes out 35 random ids from the table List.
What I would like to do to find the ids that got randomly generated, store them into a database called Status.
The purpose is to avoid duplication the next time I get a new 35 random ids from the List. So I never get the same random id twice.
Here's what I've tried, but been unsuccessful to get working.
#schedule = current_user.schedules.new
if #schedule.save
#user = User.find(params[:id])
Resque.enqueue(ScheduleTweets, #user.token)
#schedule.update_attribute(:trial, true)
flash[:notice] = "success"
redirect_to :back
else
flash[:alert] = "Try again."
redirect_to :back
end
and the worker:
def self.perform(user_token)
list = List.first(6)
#status = list.statuses.create
list.each do |list|
Status.create(list_id: "#{list}")
if list.avatar.present?
client.create_update(body: {text: "#{list.text}", profile_ids: profile_ids, media: { 'thumbnail' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png', 'photo' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png' } })
end
end
end
however the Status.create(list_id: #list) doesn't work.
Does anybody have any idea what is going on, and how I can make the list_ids get saved successfully to Status?
It's also associated:
list has many statuses, and status belongs to list
The following line of code is wrong:
Status.create(list_id: "#{list}") # WRONG
In your case the list variable is a List instance. And you're passing its string version to list_id which expects an integer.
Do this:
Status.create(list_id: list.id)
Or this:
list.statuses.create
I think the following will also work:
Status.create(list: list)

What's the right way to modify the params passed to controller in rails 3.1.0?

In our Rails 3.1.0 app, we need to modify params passed to rfq controller in create and update. For example, we want to record the current user id under input_by_id. What we did was:
#rfq.input_by_id = session[:user_id]
It worked as expected. Also when need_report field is false, then report_language field should be nil. We decide to add the following line in rfq controller to make sure the nil is passed to report_language when need_report is false:
#rfq.report_language = nil unless params[:need_report]
However this addition causes the rspec case failure (in create/update of the controller) because of the data validation failure. However when we fire up the app, it behaves fine without saving the report_language when need_report is false. I am wondering if the line above is not the right way to use params[:need_report] for #rfq updating.
Thanks so much.
UPDATE:
Controller code:
def create
if has_create_right?
#rfq = Rfq.new(params[:rfq], :as => :roles_new )
#rfq.input_by_id = session[:user_id]
#save sales_id selected
if sales? && member? && !team_lead?
#rfq.sales_id = session[:user_id]
end
#view page may carry the hidden report language even if need_report == false
#rfq.report_language = nil unless params[:need_report]
#save into join table rfqs_standards
params[:rfq][:standard_ids].each do |sid|
#rfq.standards << Standard.find(sid.to_i) if !sid.nil? && sid.to_i > 0
end unless params[:rfq][:standard_ids].nil?
#save into join table rfqs_test_items
params[:rfq][:test_item_ids].each do |tid|
#rfq.test_items << TestItem.find(tid.to_i) if !tid.nil? && tid.to_i > 0
end unless params[:rfq][:test_item_ids].nil?
if #rfq.save!
redirect_to URI.escape("/view_handler?index=0&msg=RFQ saved!")
else
flash.now[:error] = "RFQ not saved!"
render 'new'
end
else
redirect_to URI.escape("/view_handler?index=0&msg=No rights!")
end
end
Test case failed after addition of #rfq.report_language = nil unless params[:need_report]
it "should be successful for corp head" do
session[:corp_head] = true
session[:user_id] = 1
s = Factory(:standard)
rfq = Factory.attributes_for(:rfq, :need_report => true, :report_language => 'EN')
rfq[:standard_ids] = [s.id] # attach standard_id's to mimic the POST'ed form data
get 'create', :rfq => rfq
#response.should redirect_to URI.escape("/view_handler?index=0&msg=RFQ saved!")
response.should render_template('new')
end
the problem ist that you are simply not looking at the right value.
get 'create', :rfq => rfq will result in a params-hash like {:rfq => {...}}
so you need to #rfq.report_language = nil unless params[:rfq][:need_report] == 'true'

Intercepting creation of new object

I'm adding a categorization functionality to my app and struggling with it. Objects have many categories through categorizations. I'm trying to intercept the creation of a new categorization, check if theres a similar one, if so, increment it's count, if not, create a new object. Here's what I have so far.
validate :check_unique
protected
def check_unique
categorization = Categorization.where(:category_id => self.category_id, :categorizable_id => self.categorizable_id, :categorizable_type => self.categorizable_type)
if categorization.first
categorization.first.increment(:count)
end
end
This kind of logic should not exist in the controller. This is really business domain and should be in the model. Here's how you should go about it:
categorization = Categorization.find_or_create_by_category_id_and_categorizable_id_and_categorizable_type(self.category_id, self.categorizable_id, self.categorizable_type)
categorization.increment!(:count)
find_or_create will try to find the category in the DB, and if it doesn't exist, it'll create it. Now just make sure that count defaults to zero, and this code will do what you want. (when initially created the count would be 1, then later it'll increment)
PS: I'm not sure if find_or_create has changed in rails 3. But this is the main idea
I decided to move it out of the model object and put it into the controller method creating the categorization. It now works (Yay!) and here's the code if anyone is interested.
def add_tag
object = params[:controller].classify.constantize
#item = object.find(params[:id])
#categories = Category.find(params[:category_ids])
#categories.each do |c|
categorization = #item.categorizations.find(:first, :conditions => "category_id = #{c.id}")
if categorization
categorization.increment!(:count)
else
#item.categorizations.create(:category_id => c.id, :user_id => current_user.id)
end
end
if #item.save
current_user.update_attribute(:points, current_user.points + 15) unless #item.categorizations.exists?(:user_id => current_user.id)
flash[:notice] = "Categories added"
redirect_to #item
else
flash[:notice] = "Error"
redirect_to 'categorize'
end
end

Resources