One of the messier practices I have in Rails development is juggling validations of associated fields between validating the actual object (eg: validates_presence_of :related_object) and validating on the id column for that association (eg: validates_presence_of :related_object_id).
I figure I should probably start being a little more consistent with this, and before I commit to anything, I'm wondering if there's any advantage of either method over the other? I can't think of anything, but then I've been known to overlook stuff before. So, does it make any difference? Is there a convention re: what most developers do that I should abide by?
Any suggestions appreciated.
This question comes up every so often.
In most cases you will want to validate the presence of the actual associated object, not just verify that an id (which could well be invalid) has been set.
Validating association_id will also prevent you from creating the object with a new association record and saving both together.
Of course you have to check the presence of :object_id. If you check the presence of :object then this object will be fetched from your DB and then will be checked via simple blank?. I guess you won't be happy with additional DB hit.
Related
I wanted to start using attr_accessible with my models to stop the problem with mass assignment. I understand how it works and have researched as much as I could.
What I don't understand is the difference between using update_attributes(params[:my_form]) or create(params[:my_form]) and setting the fields one by one? Aren't both just as vulnerable?
What is the difference between NOT having attr_accessible and doing this...
#model_object = ModelObject.new
#model_object.create(params[:model_object_params])
And having attr_accessible and doing this...
#model_object = ModelObject.new
#model_object.field1 = params[:model_object_params][:field1]
#model_object.field2 = params[:model_object_params][:field2]
#model_object.field3 = params[:model_object_params][:field3]
#model_object.save!
Aren't both these methods of creating the record just as vulnerable? The hacker/cracker could send a url to both these methods and both would do just the same, right?
Or does using attr_accessible and updating the fields one-by-one do something different or somehow become safer?
There's where all these methods I'm finding of using attr_accessible don't make any sense to me. It seems to be doing the same thing two different ways. What am I missing?
Thanks.
In the way you are doing it, it does not prevent "mass assignment".
"Mass assignment" is the term used when Rails is handling the assigning of values to attributes in a model. This is typically done in a controller, using the names and values in params.
When you're doing the assigning yourself, it is also "mass assignment", in a way; but you have fine control over what to assign and what not to in this case. So, to save writing that boilerplate assignment code, Rails provides attr_accesible - same control, less code.
To see how it is used:
Presume that a ActivityLog model has an attribute called user_ip_address.
Now, user_ip_address is an attribute in the model, and could be assigned by mass-assignment or by "self-rolled-mass-assignment".
But in both cases that is wrong -- you don't want user-supplied input to set a value for that attribute.
Instead, you want to always find out the actual IP address of the user and assign that value (ignoring any
value in params). So you would exclude user_ip_address from attr_accessible and instead assign it yourself.
attr_accessible :all_attributes_except_user_ip_address
#al = ActivityLog.new(params[:model_object_params])
#al.user_ip_address = get_origin_user_ip_address
#al.save
For any information that a user should not be able to change, use attr_accessible and exclude it from the list.
The short answer is that it stops field4 from being set implicitly.
The difference is that without attr_accessible a hacker could update a field that is not in your form. With attr_accessible this impossible.
E.g. if your user model has a field is_admin, a hacker could try to create a new admin by posting:
params[:user][:is_admin] = true
If attr_accessible is set (and obviously it shouldn't contain is_admin) this is impossible.
About your example: if your model only has field1, field2 and field3 and there are no other database columns you want to protect, there is no need to use attr_accessible. Hope this makes it clear.
Just remember:
Without any precautions
Model.new(params[:model]) allows
attackers to set any database column’s
value.
Source: http://guides.rubyonrails.org/security.html#mass-assignment
The idea here is to limit the parameters you will accept for a given model. Then you can test each of them either with a validation or some other code to be sure they fit expected values.
Attr_accessible is intended to limit the "surface" of your model to what you intend to accept and check carefully. In this way you can automatically ignore an injected parameter like :roles => "admin" in case you add that feature to your model
user.update_attributes(params[:user])
Since the roles attribute is not listed in attr_accessible, the user's attempt to become an administrator is fruitless.
You want to handle the validation logic in one place (your model), instead of checking each parameter value in your controller.
Mass assignment isn't something you prevent, it's something you control. It's a good feature, one that makes things easier and cleaner, but without some kind of ability to control what gets set via mass assignment it's a potential security hole. attr_accessible, as others have mentioned, provides that control.
I am trying to figure out things in code written by someone else. There are two models, with simple has_many relation (A->B).
Now the problem is, that while saving the "B" model, also the "A" model is updated in the database. Now, there is no callbacks of any sort, there is no special relation conditions (:autosave, etc), and also there is no Observers in the code.
The question is, what could be other things, which define this kind of behaviour?
Update: I am trying to debug the save process to track anything, but I am getting overwhelmend by the ammount of calls to internal active_record methods, so this approchach is getting useless.
Bonus question: How can I dump current model callbacks (in case, they were added in some manner which resistant to my grepping skills).
It could have :touch => true. That auto updates the association.
This turned out to be very complicated, internal application bug with Marshaling. In the result records fetched from cache were marked as not persisted, which forced ActiveRecord to create duplicate record while saving related objects.
I'm still learning Ruby, and get caught up in alot of the 'magic', wanting to better understand what is actually happening, and making sure that I understand what it is doing.
I've got a user, and each user has entries.
In my user class, I have
has_many :entries
and in my entries class I have
belongs_to :user
I was expecting that the entries table would have a column for users, but I'm not seeing that when I 'describe' the database.
How do I know, or how does Rails know which user the entry is connected to? Or do I need to create a field myself to do that?
It seems strange to me that we have all these 'belongs_to', etc. yet it isn't explicit how that connection is made.
This is a common misconception. Associations do not create the database tables for you. Instead, you have to create them yourself. What you need to be careful of, is that an Entry model would have a user_id field, in order for the association to fully work. I truly would not want to advertise or anything, but i have created a blog post that can help you quite a lot i think :
http://www.codercaste.com/2011/02/06/rails-association-in-plain-english-what-i-wish-i-had-known-before-i-started/
I'm doing a security audit on a Rails 2.3.8 application and one of the things that has come up is our lack of attr_protected or attr_accessible in my model definitions. I understand the reasoning behind them, and have even written a gem to assist with mass assignment, but I'm looking for attributes that I might potentially be missing.
The problem I have is determining which fields should be protected. Are there any rules that people generally follow for this? I'm thinking attributes like foreign keys and booleans like admin? would make sense to protect. I'm also wondering about fields like STI type, and polymorphic *_type/*_id fields. I see that Rails 3 introduced attributes protected by default, but it doesn't appear that Rails 2.3.8 has this.
Any guidance on this would be greatly appreciated.
My general rule of thumb is that any attribute you don't want users to modify should be protected.
So in my models, I use attr_accessible for all attributes that are present as fields in forms. All others are protected. (I'd rather have everything protected by default.)
In other words: assume all data sent by clients will be maliciously tampered.
Edit: relevant blog post http://www.kalzumeus.com/2010/09/22/security-lessons-learned-from-the-diaspora-launch/
I guess every "potentially dangerous" attribute should be protected, like an admin flag for a user.
In my opinion, ideally, every model should have attr_accessible for all attributes that can be updated. It's the safer solution.
I've come across an oddity in ActiveRecord's #relationship_ids method (that's added automatically when you declare 'has_many'), which saves immediately for existing records, which is causing me some issues, and I wonder if anyone had any useful advice.
I'm running Rails 2.3.5.
Consider this simple scenario, where an article has_many tags, say:
a = Article.first
a.name = "New Name" # No save yet
a.author_id = 1 # No save yet
a.tag_ids = [1,2,3] # These changes are saved to the database
# immediately, even if I don't subsequently
# call 'a.save'
This seems surprising to me. It's specifically causing problems whilst trying to build a preview facility - I want to update a bunch of attributes and then preview the article without saving it - but in this instance the tag changes do get saved, even though no other fields do.
(Of possible relevance is that if 'a' is a new article, rather than an existing one, things behave as I'd expect - nothing is saved until I call 'a.save')
I have a fairly nasty workaround - I can override the tag_ids= method in my model to instead populate an instance variable, and actually save the related models in a before_save callback.
But I'd love to know of a simpler way than me having to do this for every model with a has_many relationship I'd like to create a preview facility for.
Does anyone have any fixes/workarounds/general advice? Thanks!
There's a reason things are this way. It's called foreign keys. In a has many relationship, the information that links to the model that has many is stored outside of that model as a foreign key.
As in Articles, has many tags. The information that links a tag to an article is stored either in the tags table or in a join table. When you call save on an article you're only saving the article.
Active record modifies those other records immediately. Except in the case where you're working with a new article that hasn't been saved yet. Rails will delay creating/updating the associated records if it doesn't know which id to place in the foreign key.
However, if you're modifying existing records, the solution you've decided on is really all that you can do. There's an even uglier hack using accepts_nested_attributes_for, but it's really not worth the effort.
If you're looking to add this behaviour to many models but not all models, you might want to consider writing a simple plugin to redefine the assigment the method you need and add the call back in a single class method call. Have a look at the source of something like acts_as_audited to see how it's done.
If you're looking to add this behaviour to all models, you can probably write a wrapper for has_many to do that.