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
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 updated my company's application from Rails 5.2.1 to Rails 5.2.2.1. Upon running our test suite post-update, I am encountering issues with validating uniqueness within the scope of a model, specifically, when appending a model to the ActiveRecord relation of another model. For example, in our application, if I were to do #person.cars << #car, we would run a uniqueness validation (validates :car_id, uniqueness: { scope: :group_id }. Even in a scenario where #person.cars was originally empty, our post-update branch is throwing validation errors on this uniqueness check. These test cases work on our master branch (pre-update), but not on our update branch (post-update). There have been no other changes made to the application besides updating Rails from 5.2.1 to 5.2.2.1. I am wondering if anyone knows of any existing bugs or issues in relation to Rails 5.2.2.1 uniqueness validations that may be causing this. I have looked through the changelogs of both Rails and ActiveRecord, as well as a few other dependencies that were updated, but I have been unable to find anything.
Looks like this is an issue with a change made in Rail's ActiveRecord::Associations which used to remove duplicates in version 5.2.1, when appending to an ActiveRecord association. This never threw a RecordInvalid exception, as the duplicate would be removed before hand. In 5.2.2.1, it looks like that has been removed, and any duplicates appending to an association will no longer be preemptively deleted (most likely to mimic Ruby += functionality). I had to change all your uses of += to a relation to |= to ensure duplicates were no longer being appended on.
Sorry for no being able to post any code or stack traces. The stack trace was very application specific and wouldn't have been helpful at all, and the code is proprietary. Appreciate the help!
To my knowledge, the new default in Rails 5 requires belongs_to associations to be present. I made a model with this association, but the problem is I don't get presence validation error when the associated field is empty. Instead I get a database Null Validation error since I set the _id column not to be null. (PG::NotNullViolation because I use Postgres)
Is this behaviour normal? I mean shouldn't I get the rails error only?
BTW, when I add presence validation for the field, it works as I expected.
According to the issue re weird behaviour of config belongs_to_required_by_default, it seems like one of your other gems intervenes in ActiveRecord::Base and causes the bug.
One of workarounds to the issue is to move the line
config.active_record.belongs_to_required_by_default = true
from initializers directly into application.rb.
This worked for me smoothly.
New Rails 5 applications come with a new initializer in
config/initializers/active_record_belongs_to_required_by_default.rb
If you upgraded a Rails 4 application or created your application with a beta version of Rails 5, then that file might be missing.
The configuration in that file enables the feature in question:
# Be sure to restart your server when you modify this file.
# Require `belongs_to` associations by default. This is a new Rails 5.0
# default, so it is introduced as a configuration option to ensure that apps
# made on earlier versions of Rails are not affected when upgrading.
Rails.application.config.active_record.belongs_to_required_by_default = true
Please check how belongs_to_required_by_default is configured in your application.
I faced with same problem.
You can move
config.active_record.belongs_to_required_by_default = false
to config/environments/needed_environment.rb or to config/application.rb
Helped for me!
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.
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