Mongoid attr_accessible not working
-
06-06-2021 - |
Question
Today morning I wake with this weird issue where mongoid was creating a record for the attributes which isn't being defined in the model
To overcome this i decide to implement attr_accessible also mention in Mongoid specification
"Providing a list of fields as accessible is simply the inverse of protecting them. Anything not defined as accessible will cause the error." -- Mongoid Specification
Think all would work fine I create a dummy record and too my surprise I got inserted as oppose to the statement above that
"Anything not defined as accessible will cause the error
Here my model structure
class PartPriceRecord
include Mongoid::Document
field :supplier_id,type: Integer
field :part_number,type: String
field :part_description, type: String
field :core_indicator,type: String
field :us_part_price,type: Float
field :us_core_price,type: Float
field :us_fleet_price,type: Float
field :us_distributor_price,type: Float
field :ca_part_price,type: Float
field :ca_distributor_price,type: Float
field :ca_core_price,type: Float
field :ca_fleet_price,type: Float
field :basic_file_id,type: Integer
index :part_number, unique: true
validates_presence_of :supplier_id
validates_presence_of :part_number
#validates_uniqueness_of :part_number
validates :part_number ,:format => { :with => /^[a-z0-9A-Z\s*-]+[-a-z0-9\s-]*[a-z0-9\s*-]+$/i ,:message => "Only AlphaNumeric Allowed" }
validates :supplier_id, :format => { :with => /^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i , :message => "Only Alphanumeric Allowed" }
#validates :part_description,:presence => true
validates :part_description,:format => { :with => /^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i ,:message => "Only Alphanumberic Allowed"} ,:allow_nil => true
validates :core_indicator ,:inclusion => { :in => %w(Y N),
:message => "%{value} is not a valid Coreindicator must be Y | N"
} ,:allow_nil => true,:allow_blank => true
validates :us_part_price,:us_core_price,:us_fleet_price,:us_distributor_price,:ca_part_price,:ca_core_price,:ca_fleet_price,:ca_distributor_price ,:format => { :with => /^([0-9]+(\.([0-9]{2}|[0-9]{1}))?)$/ ,:message => "should look like money" } ,:allow_nil => true,:allow_blank => true
@@required_attributes =[:supplier_id,:part_number,:part_description,:core_indicator,:us_part_price,:us_core_price,:us_fleet_price,:us_distributor_price,:ca_part_price,:ca_core_price,:ca_fleet_price,:ca_distributor_price]
@@not_required_attributes = ["_id","basic_file_id"]
cattr_reader :required_attributes,:not_required_attributes
attr_accessible :supplier_id,:part_number,:part_description, :core_indicator,:us_part_price,:us_core_price,:us_fleet_price,:us_distributor_price,:ca_part_price,:ca_distributor_price,:ca_core_price,:ca_fleet_price,:basic_file_id
end
and Here the record I creating from my console
ruby-1.9.2-head :003 > PartPriceRecord.count()
=> 260317 ## initial count before creating a new record
ruby-1.9.2-head :004 > p1 = PartPriceRecord.new(:customer_id => "One",:part_number => "ASA",:supplier_id => "Supp")
=> #<PartPriceRecord _id: 4fa77921d2d8d60e39000002, _type: nil, supplier_id: "Supp", part_number: "ASA", part_description: nil, core_indicator: nil, us_part_price: nil, us_core_price: nil, us_fleet_price: nil, us_distributor_price: nil, ca_part_price: nil, ca_distributor_price: nil, ca_core_price: nil, ca_fleet_price: nil, basic_file_id: nil>
ruby-1.9.2-head :005 > p1.save
=> true ## Record got created
ruby-1.9.2-head :006 > PartPriceRecord.count()
=> 260318 ## Count indicating record was created
Any idea why is this so ?
Thanks
La solution
Your question is valid -- it appears that the documentation is inconsistent, not fully correct, and somewhat outdated, from the following tests and cursory reading of Mogoid code.
Fields that are attr_protected or NOT attr_accessible ignore mass assignment; they do NOT raise an error on mass assignment.
In the section on Protected, "raising an error" is incorrect, and the documentation even mismatches User and Person. In the section on Accessible, "will cause the error" is incorrect, but the comment "silently ignore protected ones" gives a clue that no error is raised and that the mass assignment is ignored.
Here's a fragment from mongoid/spec/mongoid/attributes_spec.rb that supports this.
describe ".attr_accessible" do
context "when the field is not _id" do
let(:account) do
Account.new(number: 999999)
end
it "prevents setting via mass assignment" do
account.number.should be_nil
end
end
...
end
You must add the field customer_id to your PartPriceRecord model. My tests for User and PartPriceRecord follow. Hope that this helps.
require 'test_helper'
class PartPriceRecordTest < ActiveSupport::TestCase
def setup
User.delete_all
PartPriceRecord.delete_all
end
test "User" do
assert_equal(0, User.count())
# Set attributes on a user properly.
user = User.new(first_name: "Corbin")
assert_equal("Corbin", user.first_name)
user.attributes = { first_name: "Corbin" }
assert_equal("Corbin", user.first_name)
user.write_attributes(first_name: "Corbin")
assert_equal("Corbin", user.first_name)
# Attempt to set attributes a user, raising an error. # <-- This documentation is incorrect, no error is raised
#user = User.new(first_name: "Corbin", password: "password")
user.attributes = { first_name: "Corbin", password: "password" } # inaccessible field is forced to nil
assert_equal("Corbin", user.first_name)
assert_equal(nil, user.password)
user.write_attributes(first_name: "Corbin", password: "password") # inaccessible field is forced to nil
assert_equal("Corbin", user.first_name)
assert_equal(nil, user.password)
end
test "PartPriceRecord" do
assert_equal(0, PartPriceRecord.count())
p1 = PartPriceRecord.new(:customer_id => "One",:part_number => "ASA",:supplier_id => "Supp")
assert_equal(nil, p1.customer_id)
p1.save
assert_equal(1, PartPriceRecord.count())
assert_equal(nil, PartPriceRecord.find(p1.id).customer_id)
end
end