datamapper/dm-core — Issue #152: Error when Model.new with attributes
Author: yayugu
Created: 2011-10-12 14:47:30+00:00
State: open

Error when Model.new with attributes
because of commit: afbd387196

def attributes=(attributes)
model = self.model
attributes.each do |name, value|
case name
when String, Symbol
if model.allowed_writer_methods.include(setter = "#{name}=") # <- HERE!
__send__(setter, value)
else
raise ArgumentError, "The attribute '#{name}' is not accessible in #{model}"
end
when Associations::Relationship, Property
self.persistence_state = persistence_state.set(name, value)
end
end
end

model.allowed_writer_methods is nil

stack trace:
NoMethodError:
undefined method `include?' for nil:NilClass
# /Users/yayugu/.rvm/gems/ruby-1.9.2-p290/bundler/gems/dm-core-6031e6ef3ee8/lib/dm-core/resource.rb:332:in `block in attributes='
# /Users/yayugu/.rvm/gems/ruby-1.9.2-p290/bundler/gems/dm-core-6031e6ef3ee8/lib/dm-core/resource.rb:329:in `each'
# /Users/yayugu/.rvm/gems/ruby-1.9.2-p290/bundler/gems/dm-core-6031e6ef3ee8/lib/dm-core/resource.rb:329:in `attributes='
# /Users/yayugu/.rvm/gems/ruby-1.9.2-p290/bundler/gems/dm-core-6031e6ef3ee8/lib/dm-core/resource.rb:748:in `initialize'
# ./spec/user_spec.rb:7:in `new'
# ./spec/user_spec.rb:7:in `block (3 levels) in '

code:
user.rb
# encoding: utf-8
class User
include DataMapper::Resource

property :id, Serial
property :name, String, :length => (3..40), :unique => true
property :email, String, :length => (5..40), :unique => true, :format => :email_address
property :hashed_password, String
property :salt, String
property :created_at, DateTime
property :updated_at, DateTime
property :permission_level, Integer, :default => 1

has n, :entries

attr_accessor :password, :password_confirmation

validates_uniqueness_of :name
validates_uniqueness_of :email
validates_length_of :password, :minimum => 4, :if => :password_require?
validates_presence_of :password_confirmation, :if => :password_require?
validates_confirmation_of :password

before :valid? do
self.name = name.strip
end

def password=(pass)
@password = pass
self.salt = User.random_string(10) if !self.salt
self.hashed_password = User.encrypt(@password, self.salt) if !@password.blank?
end

def self.authenticate(name, pass)
current_user = first(:name => name)
return nil if current_user.nil?
return current_user if User.encrypt(pass, current_user.salt) == current_user.hashed_password
nil
end

def admin?
permission_level == 1
end

def password_require?
self.new? || (!self.new? && !self.password.blank?)
end

protected

def self.encrypt(pass, salt)
Digest::SHA1.hexdigest(pass+salt)
end

def self.random_string(len)
Array.new(len) { ['a'..'z','A'..'Z','0'..'9'].map(&:to_a).flatten[rand(61)] }.join
end
end

class Hash
def stringify
inject({}) do |options, (key, value)|
options[key.to_s] = value.to_s
options
end
end

def stringify!
each do |key, value|
delete(key)
store(key.to_s, value.to_s)
end
end
end

class GuestUser
def admin?
false
end

def permission_level
0
end
end

user_spec.rb
```ruby
# encoding: utf-8
describe "User" do
context "register" do
before do
@user = User.new(
:name => 'Johnny',
:email => 'johnny@example.com',
:password => 'password',
:password_confirmation => 'password'
)
end
after :each do
@user.destroy
end
it "should be able to register a user" do
@user.save.should be_true
@user.name.should eq('Johnny')
end
it "should strip spaces" do
@user.name = ' Johnny '
@user.save.should be_true
@user.name.should eq('Johnny')
end
end
end
```

when rollback to
`if model.public_method_defined?(setter = "#{name}=")`
it works fine.