Rails 3: update_attributes sets column to 'nil' - ruby-on-rails

The problem I'm having is with the method update_attributes. The code:
n is set to an Active Record object.
n = Notification.find(notification_id)
Then, n is updated with the hash notification_options.
n.update_attributes(notification_options)
The issue I'm having is when I
raise n.inspect
It shows the two fields are set to nil. Also, in the database the two fields are empty.
Why won't it update the attributes?
Let me know if I need to be more specific.

This is because you're using attr_accessor, and not attr_accessible, I would guess. Please show us your Notification model.

So it ends up that the issue was with a line in the model for a gem that being used. It needed a specific format which was causing it to set to nil if it didn't match.

Related

Find_or_initialize_by(nil) returns last record

So I'm trying to create a complicated(imo) CSV/Excel import process, which has to create records for 3 separate models + associations, and while debugging the validation for this process I have stumbled upon a confusing concept regarding find_or_initialize_by() when the passed attributes are nil.
According to Rails API Docs, find_or_initialize_by() should do the following:
# File activerecord/lib/active_record/relation.rb, line 222
def find_or_initialize_by(attributes, &block)
find_by(attributes) || new(attributes, &block)
end
Which leads me to believe that if I pass attributes to find_by which are nil or even blank it should then move it to Model.new(nil), however, for me it keeps returning the last record for that model.
Methods such as Model.find_by() and Model.where().find_or_initialize when passed nil, {}, false, "" still return the last record.
The reason I want it to initialize a new record with nil attributes is so that it fails validation and throws and error back to the user that the data entered in that row is invalid. (Since this is not a standard columns = model attributes type of import, I have to parse the passed columns through another method that should return nil if a piece of the entry is bad... at least thats the best way I can think of.)
So would anyone be able to help me understand why this doesn't work as I've explained and what your suggestion might be in this situation?
Thanks!
Which leads me to believe that if I pass attributes to find_by which
are nil or even blank it should then move it to Model.new(nil),
however, for me it keeps returning the last record for that model.
No, that's not right. find_by() always return first record matching the specified conditions, in your case there is no any conditions, so first record is returned.
It is returns nil only if conditions isn't matching:
=> Model.find_by(nil) # empty conditions without column specifying
=> #<Model:0x00561654201c30
=> Model.find_by(foo: nil) # empty conditions with column specifying
=> nil
In order to initialize model with empty atributes, use empty conditions:
=> Model.where(foo: nil, bar: nil).find_or_initialize

Rails - Get old value in before_save

I'm trying to get the old value in the before_save by adding "_was" to my value but it doesn't seem to work.
Here is my code:
before_save :get_old_title
def get_old_title
puts "old value #{self.title_was} => #{self.title}"
end
Both "title_was" and "title" got the new title just been saved.
Is it possible to get the old value inside before_save ?
The reason for you getting the same value is most probably because you check the output when creating the record. The callback before_save is called on both create() and update() but on create() both title and title_was are assigned the same, initial value. So the answer is "yes, you can get the old value inside before_save" but you have to remember that it will be different than the current value only if the record was actually changed. This means that the results you are getting are correct, because the change in question doesn't happen when the record is created.
Instead of before_save use before_update. It should work now.
So, the answer above might work but what if I wanted to get the previous value for some reason and use it to perform some task then you would need to get the previous value. In my case I used this
after_update do
if self.quantity_changed?
sku.decrement(:remaining, (self.quantity_was - self.quantity) * sku.quantity)
end
end
The _was and _changed? added to any of the columns would do the job to get the job done.
In rails 5.1.1 ActiveRecord::AttributeMethods::Dirty provides
saved_changes()
Link for saved_changes()
which returns a hash containing all the changes that were just saved.

How to refer to the current record in a Rails query?

In a Rails controller I'm using a JSON request to an external database to return integers that are used to order a collection of records:
Model.order(JSON.parse(open("http://myapp.com/models/#{:id}")).read)['attribute'])
I want to make this dynamic to aid switching between environments. Something like:
Model.order(JSON.parse(open(model_url(model))).read)['attribute'])
This is not correct, and model_url(model) is returning an error:
undefined local variable or method 'model'
How do I refer to self in query?
There must be a more elegant solution than
...JSON.parse(open("#{root_url}/models/{:id}"))....
EDIT:
Lightswitch05's answer below does anser the question I asked. The query should reference params[:id] to get the url of the current record.
In fact, I have decided to move this JSON call into a virtual attribute on the model. This means I can simply call Model.order(:my_virtual_attribute). While this solution brings its own share of issues—I needed to make url_helpers available to the model—in the long run I think this will be a cleaner solution.
As per our discussion the problem is that model is not defined. Since all you are trying to do with model is get the url to it, all you really need is params[:id]. This will fix your error message:
Model.order(JSON.parse(open(model_url(params[:id]))).read)['attribute'])
where model has been replaced with params[:id]
Change your code:
Model.order(JSON.parse(open(model_url(model))).read)['attribute'])
to:
model_tableized = Model.to_s.tableize
model_url = "#{model_tableized}_url(#{model_tableized.chomp('s')})"
Model.order(JSON.parse(open(model_url).read)["attribute"])
I think that should work.
You need the name method.
If you're using the model, and not an instance of the model, it would be Model.name
If you're using an instance, it would be
#model = Model.first
#model.class.name

Check if record exists in Rails before creating

I am trying to search my database before I enter the record, by doing this:
Product.update_or_create_by_name_and_date_and_applicationURL_and_server_and_addi_servers(app_name, app_date,url_app,server_name,addi_servers)
the problem is that I get an undefined method exception!
Is there another way to search for the same record before entering one?
You should use two steps:
#Suggestion 1
obj = Product.find_or_create_by_...
#Suggestion 2
obj = Product.find_or_initialize_by_...
obj.update_attributes hash_here
Rereading, your question, I can't really understand what do you want to update if you try to find an object with known attributes. Anyway, you would just have to adapt my answer a little if some fields are for identifying and some for update.
I would define a function in your model: something like
Product.find_by_everything
where you write out all the parameters of the search, instead of using the the long naming method.
Then, if that returns nil, create the product. This doesn't seem to be a good use case of using the built in activerecord naming methods.

Rails: Getting column value from query

Seems like it should be able to look at a simple tutorial or find an aswer with a quick google, but I can't...
codes = PartnerCode.find_by_sql "SELECT * from partner_codes where product = 'SPANMEX' and isused = 'false' limit 1"
I want the column named code, I want just the value. Tried everything what that seems logical. Driving me nuts because everything I find shows an example without referencing the actual values returned
So what is the object returned? Array, hash, ActiveRecord? Thanks in advance.
For Rails 4+ (and a bit earlier I think), use pluck:
Partner.where(conditions).pluck :code
> ["code1", "code2", "code3"]
map is inefficient as it will select all columns first and also won't be able to optimise the query.
You need this one
Partner.where( conditions ).map(&:code)
is shorthand for
Partner.where( conditions ).map{|p| p.code}
PS
if you are often run into such case you will like this gem valium by ernie
it gives you pretty way to get values without instantiating activerecord object like
Partner.where( conditions ).value_of :code
UPDATED:
if you need access some attribute and after that update record
save instance first in some variable:
instance=Partner.where( conditions ).first
then you may access attributes like instance.code and update some attribute
instance.update_attribute || instance.update_attributes
check documentation at api.rubyonrails.org for details

Resources