Rails 3.2.x associations and attr_accessible - ruby-on-rails

Trying to find the definitive answer on whether active record associations should be in the list of attr_accessible attributes.
I've seen
class Foo
attr_accessible :name
attr_accessible :bars
belongs_to :bar
end
also seen
attr_accessible :bars_id
want to know the proper way to be able to do Foo.new(name: 'name' bar: barvar)

As often the definitive answer is: "It depends™"
Only the attributes you want to mass-assign should be made accessible.
So if you want or need to do…
Foo.new(name: 'name', bar: barvar)
…then you simply have to make bar accessible.
In the end assign_attributes is called which does a simple send("#{attribute_name}=", attribute_value) after checking the accessibility of the attribute.
Some coding style aspects:
Often mass assignment happens when processing the param hash. At least that's where the security problems are lurking. There you rarely have a Bar object but more often a bar_id.
However if you work with model instances, most people prefer using the association methods (as #Andrew Nesbitt wrote) because that often has some advantages (automatic saving, automatic update of the association counterpart, cleaner code, …)
So there are reasons to have one or the other or both.
My personal opinion: One should not waste a lot of time on this topic since Rails 4.0 will have a better solution for parameter sanitizing. (See strong_parameters if you want it in Rails 3, too)

You can avoid needing to make bar_id accessible by using the association builder:
# singular (has_one)
foo = bar.build_foo(name: 'name')
# plural (has_many)
foo = bar.foos.build(name: 'name')
The only time you would need to make an association accessible is if you are using accepts_nested_attributes.

While you can avoid making bars_id (shouldn't that be bar_id?) accessible in your example, the question is if parts of your application still needs access to it. Using active_admin, I had to make the whatever_id accessible to make things work with relations.

Related

Implications of Having an object_id Column in Rails

What are the implications of having a object_id / object_type on a model (for a polymorphic association) in regards to Object itself containing an object_id and that overriding it (http://ruby-doc.org/core-2.3.1/Object.html#method-i-object_id)?
class Event
belongs_to :object, polymorphic: true # object_id/object_type
end
When I search for object_id through the whole codebase of one of my rails projects (including all gems), I can see over 200 hits. In Rails only, this is about 50 hits.
I'd expect problems with records comparison, using them as hash keys, putting them to sets, perhaps also duplicating them with dup. In Rails, record.object_id is referenced in caching, has_many_through associations, AREL, pretty printing the record, minitest expectations, also in pry debugger,
But just from quick-looking trough the code it is very hard to guess if it will cause problems or not and I generally tend to be very defensive about such potential problems - you'll never know for sure if your next usage of the object will not break things in a way that is both very hard to debug and perhaps impossible to fix.
As I said above, I'd be very curious if you tried, but myself would rather name it belongs_to :thing, polymorphic: true or better yet something even more specific.
If you attempt to define object_id on a class you'll find that you get the following angry warning from the Ruby interpreter warning: redefining 'object_id' may cause serious problems (try it from IRB). That sounds scary - and the incidents may be tied to specific versions of Ruby (and vary based on the version used). I'd recommend fixing this.
I believe you can belong_to object, while defining the foreign_key to something else, like foreign_key: :object_identifier. That way you dont have to worry about object_id.
I think the best to follow this documentation Active Record Associations, I think defining another object_id will make you sustain the relation manually in your code and you will lose Active Record features for doing that.

attr_accessible, attr_accessor, I would like to know what they do

I'm doing my first steps in Rails and in object-oriented programming.
There is something quite fudemental that I would like to understand: why do we need attr_accessible within the model?
I have read that hackers can use mass-assignment in order to change database entries and therefore compremise security, and that's why sensitive fields need protection (using atribute_protected in this case).
Is attr_accessible the opposite of atribute_protected? If so, why do we need to state which fields are accessible and which are not? aren't those fields accessible by defult? And what is attr_accessor used for?
I noticed that if I don't make some fields acessible, my application doesn't run. Can I use attr_acessible for sensitive fields like :password_digest and :admin?
It would be amazing if someone could explain it to me.
All the best,
TimmyOnRails
You've got a couple of concepts mixed together here, so I'll try to untangle them.
attr_accessor is for setting up a readable and writable attribute. It is the equivalent of saying attr_reader and attr_writer. Since your question isn't directly about attr_accessor, I won't address it anymore than saying check out this link on Accessors.
According to the Rails docs: attr_accessible is the opposite of the attr_protected macro
You're correct that these methods are used to prevent Mass Assignment vulnerabilities.
attr_accessible says which attributes can be set by mass assignment.
attr_protected says which attributes cannot be set by mass assignment.
So what's the use case for each? In one case you're able to set a global config option that makes it so that all attributes must be declared attr_accessible:
config.active_record.whitelist_attributes = true
In that case you'd use attr_accessible frequently.
And attr_protected? If you went the opposite way and said false on whitelisting attributes, how would you declare which attributes shouldn't be mass assignable? If you said attr_protected you're right! :D
Typically you'd want to set fields like :admin as attr_protected because you don't want an attacker coming in and escalating their privileges to an admin role.
Mass assignment is not something that's easy to get right. Big, smart development teams have gotten this wrong. So tred carefully and make sure you understand what's going on!

Rails Best Practice for User-Configurable Global Attribute "Defaults"

Sorry about the awkward phrasing of the title -- not quite sure of the best way to title this but here's what I'm seeing assistance with:
In a Rails app, let's say we've got a model for a Product, and one of the attributes of the product is Price.
On the admin side of my app, I'd like to be able to set a "default" price that could be referred to if any new Product created isn't assigned a Price. If a Product does have a value for Price, then it would be used.
This is, of course, an example -- and I ask this question because I've got to imagine this is a common pattern. This can be applied to any resource that might have user-configurable global defaults or resource-specific values.
In pure Ruby, this would be solved, I think, with a class variable, so I'd be able to define ##default_price within the Product class and be able to refer to Product.default_price if the instantiated object's value doesn't exist.
My research here has pointed me towards the rails-settings-cached gem, which would allow for something like MyApp.default_price, but I'm wondering if there's a more elegant (non-plugin) way to accomplish this within the base Rails framework.
Note I'd like to setup this structure in code, but I want to be able to define the actual values through my app (i.e. config files aren't the solution I'm looking for).
Can someone enlighten me with the Rails way of handling this?
ActiveRecord picks up default attribute values from the database schema. However, these are baked into the migration and table schema and not configurable.
If you want configurability, the pattern that I've used is a before_validation callback method to set a value if the attribute is blank, e.g.:
class Product < ActiveRecord::Base
before_validation :set_price_if_blank
validates :price, :presence => true # sanity check in case the default is missing
has_one :price
private
def set_price_if_blank
self.price = Price.default if self.price.blank?
end
end
class Price < ActiveRecord::Base
def self.default
##default ||= Price.where(:default => true).first
end
end
This assumes that your price table is populated with a row that has a default flag. You could achieve this, e.g. through a seeds.rb file. I've added a validation rule to make sure that you still get an error if no default exists. It adds robustness to your application.
Also note that it's best to use Integers or Decimals for price data, not floats. See this answer.

Do I need to use attr_accessor?

I am planning to use conditional validations along the lines of what is described in this railscast In the railscast, which is rather old, attr_accessor is used, (skip to the later portion of the video to see the code). I am relatively new to rails programming and wanted to read up on what attr_accessor does. This post asks about using it and the most upvoted answer says that they should hardly ever be used in rails.
Is it necessary/should I be using attr_accessor like is done in the railscast? Or are these methods automatically created? Is there any danger to using attr_accessor in this case?
Using attr_accessor has nothing to do with Active Record. I discuss how it works in this post, that is also related to AR.
Now, what AR does do, is it automatically creates is own "accessor" methods (e.g. x/x=) based on the database model. These automatically created methods are really just stubs that it uses to proxy into the internal AR workings.
The point is, attr_accessor (automatically) wraps simple instance variable access, while AR (automatically) created methods wrap AR magic. The two operations are mutually exclusive. Because attr_accessor does not "link to" the AR magic, all it can be used for creating transient fields which are not persisted: AR does not know of or care about instance variables.
The "danger" comes from perhaps complicating the model objects with transient information -- if it is transient, why should it be part of a model object? This is the argument the most up-voted answer in the linked question makes.
Happy coding.
However, I do no know what would happen if using attr_accessor for the same field as that which happens to be in the AR model... confusion at the least.

How does this stop mass assignment?

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.

Resources