I'm trying to use strong parameters in a single model in my Rails 3 project that has around 40-50 models.
I've done the following, but when I try to create or update an instance of this model, I get the same error regarding mass assignment, as below, which shows every field of the model.
I've tried removing the accepted_nested_attributes_for from the model and restarting the webserver, but it didn't have an effect on the error I'm receiving.
config/application.rb
config.active_record.whitelist_attributes = false
app/models/my_service.rb (concatenated for brevity)
class CallService < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
belongs_to :account
has_many :my_service_chargeables
accepts_nested_attributes_for :my_forward_schedules, allow_destroy: true
validates :start_date, :username, :account_id, :plan_id, presence: true
audited associated_with: :account
scope :enabled, where(enabled: true)
scope :within, lambda{|month| where(start_date: (month.beginning_of_month..month.end_of_month))}
end
app/controllers/my_services_controller.rb
def update
#my_service = MyService.find(params[:id])
if #my_service.update_attributes(permitted_params.my_service)
flash[:success] = "Service Updated"
redirect_to #my_service
else
render 'edit'
end
end
app/controllers/application_controller.rb
def permitted_params
#permitted_params ||= PermittedParams.new(current_user, params)
end
app/models/permitted_params.rb
class PermittedParams < Struct.new(:user, :params)
def my_service
if user && user.role?(:customer)
params.require(:my_service).permit(*service_customer_attributes)
else
params.require(:my_service).permit!
end
end
def service_customer_attributes
[:timeout, :pin, :day]
end
end
ERROR WHEN UPDATING
ActiveModel::MassAssignmentSecurity::Error in MyServicesController#update
Can't mass-assign protected attributes: account_id, plan_id, start_date, username
I've run a debugger to confirm the code hits the params.require(:my_service).permit! line from the PermittedParams class, yet this exception still keeps getting thrown, when as far as I can tell, there should be nothing causing this model to require declaring attributes as attr_accessible's.
Can anyone shed some light on this behavior?
I'm using gem versions (from my Gemfile.lock):
strong_parameters (0.2.0)
rails (3.2.11)
I'm not sure what your exact use case is, but doing params.require(:my_service).permit! still seems like a bad idea here, at the very least someone could still override your model's PK. Rather than params.require(:my_service).permit! why not do:
params.require(:my_service).permit(:timeout, :pin, :day, :account_id,
:plan_id, :start_date, :username)
Or keep these in another array and merge them with your existing service_customer_attributes to keep it DRY.
This would take care of your mass assignment error, and will be more secure and more explicit.
Related
I am tring to create a scope which find out all contacts with 0 address. Got error message ArgumentError: tried to create Proc object without a block when running command 'Contact.noaddress' in rails c.
Here is my contact model including scope:
class Contact < ActiveRecord::Base
attr_accessible :email, :firstname, :lastname, :mobilephone, :fullname
has_many :addresses
validates_presence_of :firstname, :lastname
scope :noaddressed, lambda do |addresses|
joins(:addresses).where('addresses.created_at.empty?', true)
end
end
and here's address model
class Address < ActiveRecord::Base
attr_accessible :city, :country, :postalcode, :region, :street
belongs_to :contact
end
Could somebody help me please?
It sounds like a (precedence issue?) referenced here.
If you change the scope to:
scope :noaddresses, (lambda do
joins(:addresses).where('addresses.created_at is null')
end)
or
scope :noaddresses, lambda { joins(:addresses).where('addresses.created_at is null') }
Also, I don't see where you're using the block argument |addresses|. Did you forget to use it? Otherwise, you can remove it and its surrounding pipes.
Updated: I removed the |addresses| argument and updated the query to be valid SQL syntax.
I recently upgraded an app to rails 3.2.2.
I'm using Factory_girl
Factory.sequence :name do |n| "name-#{n}" end
Factory.define :user do |u| u.first_name{ Factory.next(:name) }
u.last_name { |u| 'last_' + u.first_name } u.password 'secret'
u.password_confirmation { |u| u.password } u.sequence(:email) { |i|
"user_#{i}#example.com" }
end
and this simple test
specify { Factory.build(:user).should be_valid }
generate the following warning
DEPRECATION WARNING: You're trying to create an attribute user_id'.
Writing arbitrary attributes on a model is deprecated. Please just use
attr_writer` etc. (called from block (2 levels) in
at...
How can I get rid of it?
It's probably because you haven't prepared/migrated your test database with updated column definitions, thus it thinks you're trying to arbitrarily set the attribute.
Run rake db:test:prepare to make sure it's updated.
Here's the source code of that method, where you can see Rails checks for the column or attribute first, then warns if they're not found.
I've met the same warning with the following code:
Ad model:
class Ad < ActiveRecord::Base
belongs_to :user
end
Factories:
FactoryGirl.define do
factory :ad do
association :user
end
end
FactoryGirl.define do
factory :user do
first_name {Factory.next(:first_name)}
last_name {Factory.next(:last_name)}
email {|x| "#{x.first_name}.#{x.last_name}#{Factory.next(:count)}#test.com"}
password Forgery(:basic).password
confirmed_at Date.today << 10
end
end
Test
require 'spec_helper'
describe Ad do
before(:each) do
#ad = Factory.build(:ad)
end
"it is not valid without a user"
end
Running the test gave me a similar error.
Adding
attr_accessor :user
to the Ad model fixed the warning.
I hope it helps.
I had this same warning while doing tests in Rspec and my issue was that I had a Parent model and Child model where I accidentally had this:
class Child < ActiveRecord::Base
belongs_to :parent
end
......
class Parent < ActiveRecord::Base
belongs_to :child
end
I'm new to Ruby on Rails and I'm hung up on using Active Record callbacks. I know how to use them, but I'm trying to truly understand what is happening, and I'm not getting it. My confusion has to do with variable scopes in Ruby.
Here is a simple Active Record class for a user with fields: email, password_hash, password_salt
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
#validation
validates :password, :confirmation => true
validates :email, :password, :presence => true
validates :email, :uniqueness => true
#When saving the user, encrypt the password
def encrypt_password
#First check if the password is present
if (password.present?)
#encrypt the password
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
In the method "encrypt_password", how is the variable "password" accessible? Is it the same as self.password (object var?), and is this not the same as #password? (why?)
In the actual encryption routine, I invoke self.password_salt. I noticed that I can simply type in "password_salt" (without reference to self) and it doesn't work. Why not? Why is this different from #password_salt?
Sorry if this comes across as noobish, I've spent a good couple of hours bashing away at this, and I'm struggling to understand this.
1) It is the same as self.password. ActiveRecord defines methods, not instance variables to access stuff related to the database. That's why you cannot access it with #password.
2) You need to use self.password_salt= because otherwise you'd be assigning a local variable, not doing a method call.
PS: Callbacks are only method calls on your object. The only difference is that Rails calls them for you, not yourself.
I'm still earning my stripes in Rails and have ran into a problem I can use some help on. I'm building an app that has various models (stories, photos, artwork, etc.) that a user can comment on, as well as the comments themselves. I have 98-99% of the functionality working but am stuck on getting the redirect to redirect to the top-most parent (a story, photo, etc.) after the comment has been created.
My comment model look like this:
# /app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :commentable, :polymorphic => true
has_many :comments, :as => :commentable
end
...I have several models that a user can comment on, for example a story model:
# /app/models/story.rb
class Story < ActiveRecord::Base
has_many :comments, :as => :commentable
end
My comments controller looks like this at this point:
# /app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def index
#commentable = find_commentable
#comments = #commentable.comments
end
def new
#commentable = find_commentable
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
redirect_to :back
else
render :action => 'new'
end
end
protected
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
end
...And of course my routes look like this:
# /config/routes.rb
resources :comments do
resources :comments
end
resources :stories do
resources :comments
end
The particular line I need to change is the redirect_to :back line (everything else, the polymorphism, the recursion of comments, etc. works fine). The current code works as intended when a user is commenting on a story but it's not ideal when a user is commenting on a comment because the form for that functionality is not on the story "show" page (perhaps it needs to be?).
What I have tried to do (and what I suspect the solution might be) is a method that finds the parent object and recurses when that object is a comment. My previous attempts at doing this has not been clean at all and I have yet to get a working prototype working.
I used this railscasts episode to base the majority of my code but the redirect_to :id => nil doesn't work for me as the create comment method is somehow called and it results in a NilClass error when it attempts to build comments (perhaps something is wrong with my routing as I don't see how the index action would call create?).
So Rails experts, what am I doing wrong? What do I need to do here to get this working? I feel like I'm 99% there but that last 1% is driving me crazy.
Thanks in advance...
OK i had to read this a couple times...
#comment.commentable
would return an instance of Story or whatever object that did the comment.
Solved this...It's probably not the cleanest but it works:
I first added a method in comments controller...
def get_master
#parent = #comment.commentable
if #parent.respond_to?('commentable_type')
#comment = #parent
get_master
else
return #parent
end
end
Then I changed my redirect_to to call this method in the create controller.
The key was understanding that #object.respond_to? was what I needed to do check if a method is defined.
Here's a full example of how it works: http://t.co/N6WIGzuW
I've got a model setup where a user can create a quiz with many questions and many answers on each question
The models look like this:
model Page < AR::Base
end
model Quiz < Page
has_many :questions
accepts_nested_attributes_for :questions, :allow_destroy => true
end
model Question < AR::Base
belongs_to :quiz
has_many :answers
accepts_nested_attributes_for :answers, :allow_destroy => true
end
model Answer < AR::Base
belongs_to :question
end
And my form looks like this:
= form_for #quiz do |f|
f.fields_for :questions do |qf|
# fields omitted, have fields for id, content, etc
qf.fields_for :answers do |af|
# fields omitted, have fields for id, answer, etc
f.submit 'save'
Everything works wonderfully when I edit just the quiz or when I add new questions and answers, but when I edit existing questions and answers, the changes aren't persisted in the DB. I can see the correct nested parameters being sent into the controller and when inspected the #quiz after calling update_attributes it shows the updated questions and answers but they aren't being persisted after the page is updating.
I've never had this sort of issue before and am having trouble spotting the cause, can anyone share some insight?
Thanks!
As requested, controller code: (Quiz is an STI subclass of Page)
PagesController < ApplicationController
def update
#page = #section.pages.find(params[:id])
if #page.update_attributes(params[#page.type.downcase.underscore])
redirect_to online_course_section_pages_path(#online_course, #section), :notice => "Your page has been updated"
else
render :edit
end
end
end
EDIT:
Found the problem was because of using #page.type.downcase.underscore instead of #page.type.underscore.downcase so update attributes was being passed nil instead of the actual data
Found the problem was because of using #page.type.downcase.underscore instead of #page.type.underscore.downcase so update attributes was being passed nil instead of the actual data