Is there a way I can know what attributes are updated in my model? I only want to do a validation on a user when a certain attribute was posted. This would actually be the hash that is sent via the params
eg:
#user.update_attributes(params[:user])
Thanks.
This is available within the ActiveRecord::Dirty module, which is included by default.
The changed method will give you a list of attributes with unsaved changes. The changes method will give you a hash of unsaved changes, where the keys are the attribute names and the values are an array consisting of the original and new value.
For example:
#user.changed # => ['name', 'age']
#user.changes # => { 'name' => ['Bill', 'John'], 'age' => [18, 21] }
Related
I have an ActiveModel "form object" which "has many" patients (another ActiveModel "form object"). The idea being the user can fill in the form and add as many patients.
- #form.patients.each do |patient|
= form.fields_for 'patients[]', patient do |patient_form|
This worked fine in Rails 4 and as far as I remember inputs where named something like patients[][name].
This was an Array in params such as { patients: [ {name: 'foo'} ] }.
However it seems this may have changed with Rails 5, looking at the source it seems if name ends in [] and there is no index given it will try and insert an id.
Giving an input name such as patients[1][name].
However the form object (ActiveModel) has no #id method and I get an NoMethodError. And even if it did this would give a params has which would be a Hash such as { patients: { '1' => { name: 'foo' } } }.
If I just do form.fields_for 'patients', patient all input have the same name and thus overwrite each other in params.
One solution is to add a "fake" #id method to the "form object":
# form object (ActiveModel)
def id
SecureRandomn.hex(10)
end
This will give inputs named as such: patients[f0858de30df23c3e2305][name].
Then in the controller I can convert the params hash ({ id => attributes, id => attributes, ... }) to an array of attributes ([attributes, attributes, ...]):
params[:patients].values
While I don't mind 'fixing' the params too much adding a useless #id method to the form seems too much.
I'm trying to do update_attributes with Mongoid in a Rails 3 application
The problem I'm running into is this:
Let's say my collection has the following fields:
{"Name" : "foo", "email" : "bar" }
Here's the scenario
if I do this:
#person = Person.where(:Name => "foo", :_id = "some_id")
and then I do this:
#person.update_attributes(:Name => "baba-fooka", :Last_Name => "baba-bara")
The line of code above updates the record in mongodb, but also adds a new field to the document.
How can I use the update_attributes method with a validation which doesn't allow inserting fields which don't already exist
It sounds like what you want is allow_dynamic_fields set to false in the mongoid config file. Dynamic fields is on by default which allows attributes to get set and persisted on the document even if a field was not defined for them.
Go into config/mongoid.yml under options set allow_dynamic_fields: false. It should already be there but commented out and set to true. Make sure it says false.
I was wondering, when you create an object you can often set multiple attributes in a single line eg:
#object = Model.new(:attr1=>"asdf", :attr2 => 13, :attr3 => "asdfasdfasfd")
What if I want to use find_or_create_by first, and then change other attributes later? Typically, I would have to use multiple lines eg:
#object = Model.find_or_create_by_attr1_and_attr2("asdf", 13)
#object.attr3 = "asdfasdf"
#object.attr4 = "asdf"
Is there some way to set attributes using a hash similar to how the Model.new method accepts key-value pairs? I'm interested in this because I would be able to set multiple attributes on a single line like:
#object = Model.find_or_create_by_attr1_and_attr2("asdf", 13)
#object.some_method(:attr3 => "asdfasdf", :attr4 => "asdfasdf")
If anyone has any ideas, that would be great!
You want to use assign_attributes or update (which is an alias for the deprecated update_attributes):
#object.assign_attributes(:attr3 => "asdfasdf", :attr4 => "asdfasdf")
#object.update(attr3: "asdfasdf", attr4: "asdfasdf")
If you choose to update instead, the object will be saved immediately (pending any validations, of course).
The methods you're looking for are called assign_attributes or update_attributes.
#object.assign_attributes(:attr3 => "asdfasdf", :attr4 => "asdfasf") # #object now has attr3 and attr4 set.
#object.update_attributes(:attr3 => "asdfasdf", :attr4 => "asdfasf") # #object now has attr3 and attr4 set and committed to the database.
There are some security concerns with using these methods in Rails applications. If you're going to use either one, especially in a controller, be sure to check out the documentation on attr_accessible so that malicious users can't pass arbitrary information into model fields you would prefer didn't become mass assignable.
I've given up hours of my day trying to accomplish this simple thing in Rails 3.1 with no luck. I've got some models nested 2 levels deep and associated many-to-one with belongs_to/foreign key, like:
TopLevelModel:
MiddleLevelModel:
BottomLevelModel
I am eagerly loading the whole hierarchy in my queries like so:
#model = TopLevelModel.find(1, :include => {:middle_level_children => :bottom_level_children})
The JSON serializer works fine for serializing the nested hierarchy (using the :include option), but this isn't enough for my purposes and I need a (ruby) hash representation of the record's attributes. #model.attributes() would be perfect but it neglects my relations. Is there a way to get a nested hash representation using this method (I read the documentation thoroughly and suspect not, but maybe there's some exotic option I don't know about). To be clear, the representation I am looking for would be:
{
:attribute_1 => 'some attribute', #an attribute of top level model
#...
:middle_level_children: => [{ # type 'MiddleLevelModel'
:attr_1 => 'some attribute of middle level model',
# ...
:bottom_level_children => [{ #type 'BottomLevelModel'
:attr => 'some attribute of bottom level model'
}]
}]
}
This seems like an incredibly simple (and, I would think, common) need, but I've had no luck.
Why can't you iterate through all your child relationships and print all the attributes for each instance of them?
Might be a little hokey but give Hash.from_xml a whirl.
Use the object's to_xml method to serialize with associations and then deserialize with the Hash.from_xml class method.
xml = #model_instance.to_xml(:include=>:middle_level_children)
nested_hash = Hash.from_xml(xml)
I wrote this retrieval statement to check if an appointment being saved or created dosent conflict with one thats already saved. but its not working, can someone please point me to where I'm going wrong?
#new_appointment = :appointment #which is the params of appointment being sent back from submit.
#appointments = Appointment.all(:conditions => { :date_of_appointment => #new_appointment.date_of_appointment, :trainer_id => #new_appointment.trainer_id}
)
the error is from the :date_of_appointment => #new_appointment.date_of_appointment this will always be false as:
thank you
At face value, there doesn't appear to be anything wrong with your syntax. My guess is that #new_appointment isn't containing the values you're expecting, and thus the database query is returning different values than you expect.
Try dumping out #new_appointment.inspect or check the logfiles to see what SQL the finder is producing, or use
Appointment.send(:construct_finder_sql, :conditions => {
:date_of_appointment => #new_appointment.date_of_appointment,
:trainer_id => #new_appointment.trainer_id
})
to see the SQL that will be generated (construct_finder_sql is a protected ActiveRecord::Base method).
Update based on your edit
#new_appointment = :appointment should be something like #new_appointment = Appointment.new(params[:appointment]). :appointment is just a symbol, it is not automatically related to your params unless you tell it to.