I'm currently in the process of upgrading an application from Rails 2.3.8 to Rails 3.2.7, and am having some trouble with mass-assignment.
When I try and save any model, I get the following error:
Can't mass-assign protected attributes: a,b,c,d
I noticed that Rails had set the default for whitelisting attributes to:
config.active_record.whitelist_attributes = false
So I changed it to true, but the errors kept coming up. We use attr_protected for a few things but it seems to ignore those and protect everything. I'm guessing it is due to the model using 'accepts_nested_attributes_for', but those are necessary.
Is there any other way to solve this problem without using 'attr_accessible'?
Any time you use attr_accessible or attr_protected, you have enabled mass assignment protection for that model. If the website is purely for internal use as you mention in your comments, the only way to solve this without using attr_accessible, would be to remove attr_protected from the model or any models that it touches using accepts_nested_attributes_for.
Related
I have a rails engine which encapsulates a piece of my application's funtionality. I have a bunch of models in the engine, which have various belongs_to associations defined. As of rails 5 these associations are supposed to be required by default, unless optional: true is specified in the definition.
I’m still able to create instances of the models without any validation errors. I haven’t specified optional: true on any of the associations, nor is the config optionconfig.active_record.belongs_to_required_by_default set anywhere. Besides, it was removed in rails 6 anyway.
I can't think of any reason the model instances would not fail validation. I would expect any instances of any model with an undefined belongs_to association would be invalid and raise an error. Why would these records pass validation?
I found my problem, thanks to #MatthiasWinkelmann for the tip. It turns out my engine was not calling load_defaults at all. I needed to add the following to spec/dummy/config/application.rb:
module Dummy
class Application < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f
... etc ....
end
end
here is an article containing more explanation:
An upgraded Rails gem does not upgrade your Rails configuration
I probably would have done better to mention in my question that I'm in the process of upgrading my application from Rails 4.2 to 6.1. The change was introduced in Rails 5.
I'm working on upgrading a Ruby 2.2.2 (Rails 4.1) app to Ruby 2.5.7 (Rails 5.2) and for a couple of models I'm getting some errors
From searching around, it sounds like there are some generic activerecord validation rules / messages? The messages are:
Status is invalid
User is invalid`
I am a novice at best with Ruby - so any suggestions on the best way to work through this error are appreciated!
In Rails 5, whenever a belongs_to association is defined, it is required to have the associated record present by default. That means, compared to Rails 4, each belongs_to :foo association basically adds internally a validate :foo, presence: true to the code too.
You have two choices:
Follow the new Ruby on Rails conventions and fix your tests by adding all required associated objects to the models.
Switch back to the old behavior for these kinds of associations by adding , optional: true to each belongs_to :foo line in your code.
There is actually the third option to switch off this behavior in the whole application, by adding a line like this to your application.rb
Rails.application.config.active_record.belongs_to_required_by_default = true
But that means your application will not follow Ruby on Rails conventions and defaults anymore and IMHO this ofter leads to problems with a later update.
Therefore my advice is: Fix your tests now and only make those associations optional that are really optional from the user's point of view – this might take a bit longer but causes certainly less trouble in the future.
I am upgrading from Rails 3.2 to 4.2 and wanted to follow Ryan Bates' advice of getting things working as quickly as possible before doing any major refactoring.
To that end, I installed the protected_attributes gem because I was under the impression that with this gem installed I wouldn't need to implement the strong params approach in my controllers immediately and could continue using attr_accessible in the models until I have time to refactor.
I'm not getting any errors about attr_accessible itself, but when I try to create a user in development I get Unpermitted parameters: first_name, last_name, phone despite having all of those as arguments in the User model's attr_accessible method.
Can someone point out what I'm doing wrong here?
That's not the correct approach. Instead of porting a legacy, deprecated feature from 3.2 to 4.2, what you really want to do instead is the opposite: install strong_parameters gem in Rails 3.2 and make sure to replace the attr_accessible before the upgrade.
Rails 4.x is not really designed to use protected attributes anymore, therefore you will encounter a lot of issues trying to reintroduce it.
To use strong params you will have to update your controller's code (which is what I recommend to do, since it won't cost too much work).
In general the implementation of using strong_parameters is as follows:
def create
#model = Model.create(model_params)
if #model.persisted?
# logic
else
#logic
end
end
private
def model_params
params.require(:model).permit(:model_attrbite1, :model_attribute2)
end
I just spent quite some time trying to resolve a virtual attribute issue in my model. It turned out I'd simply forgotten to add it to attr_accesible in my model. Granted I should have caught it earlier or better should have started the whole endeavor by adding it to attr_accessible in the first place.
To keep this from happening again, is there a configuration setting I can flag to throw an exception on development if I try to mass assign something and validate it when it is protected/inaccessible? I know I can use set config.active_record.whitelist_attributes = true to require whitelist for all but my question is more on an individual attribute basis.
The line above for example does not warn me if I have a model with attr_accessible :name then later add :nickname (virtual or not), and try to mass assign it checking for presence=>true. I want it to warn me that I tried to validate a protected attribute through mass assignment.
Rails 3.2 has a configuration option to raise a ActiveModel::MassAssignmentSecurity::Error in that case
config.active_record.mass_assignment_sanitizer = :strict
See Rails 3.2 release notes and the commit in Rails
Is there a way to have rails raise an error if an attempt is made to mass-assign attributes that aren't allowed by attr_accessible?
This would be handy in development to remind me why my shiny new model isn't working, and also good to log in production in order to detect malicious activity.
I'm using rails 2.3.8 but will probably soon be migrating to 3.
As of Rails 3.2 this no longer requires monkeypatching -- rails provides this behavior now. Put this in development.rb and test.rb:
config.active_record.mass_assignment_sanitizer = :strict
I would suggest something like the Bento project has incorporated into their Rails app.
They create a Rails Initializer under config/initializers/ and then override the appropriate method in the ActiveModel class to raise a MassAssignmentError (within non-production environments).
I am not sure if this would work, but you could write a test to see if your object "respond_to(:unexpected_attr)". You can then tried to force feed it that attr
Alex