Rails NoMethodError on .save - ruby-on-rails

I ran the code #transaction = Transaction.new Then I gave it some values:
<Transaction id: nil, debit_uri: "d8hmFJ89CIQUZMBoiPMnvWkQJW/bank_...", credit_uri: "d8hmciqLOg9bCIQUZMBoiPMnvWkQJW/cards...", seller_id: 2, buyer_id: 6, product_id: 31, price: #<BigDecimal:b4a6115c,'0.45E2',9(36)>, ship_price: #<BigDecimal:b4a61094,'0.123E3',9(36)>, ship_method: "fedex", created_at: nil, updated_at: nil>
but when I do #transaction.save! bang(!) or not I get the error:
NoMethodError: undefined method `clear' for nil:NilClass
from /home/alain/.rvm/gems/ruby-1.9.3-head/gems/activemodel-3.2.13/lib/active_model/validations.rb:194:in `valid?'
so I don't know where to look for the error being how my model has little to nothing and there is no method called clear.
class Transaction < ActiveRecord::Base
attr_accessible :buyer_id, :credit_uri, :debit_uri, :price, :product_id, :seller_id, :ship_method, :ship_price
require 'balanced'
attr_reader :errors
end

Regarding to Rails codebase, the error comes from:
attr_reader :errors
Look here. Try to remove it from your model.
Why?
Since you override the errors attributes and did not set it when creating your transaction instance, Rails is trying to do:
nil.clear

Related

Rails how to improve if record exists?

I have this model:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last
end
end
As you can see, I have a method to get the last event for the device. Now, elsewhere in the Device model I have this method:
def place
self.last_event.place
end
Now, if I don't have any records in Events for this Device I get an error "undefined method `place' for nil:NilClass".
And so I added:
def place
self.last_event.place if self.last_event.present?
end
And this pattern repeated itself throughout the app, I had to add "if self.last_event.present?" so it won't crash in other places too.
I am sure there must be a better way to handle this kind of thing without the need to check if last_event is present everywhere?
Any suggestions?
Thanks,
The try method (an addition of ActiveSupport) allows exactly that. If called on a nil object, it will just return nil too. Thus, both of the following lines are equivalent:
self.last_event.try(:place)
# equivalent to
self.last_event.place if self.last_event
Another option would be to have the method return a blank object which would respond to calls:
class Device < ActiveRecord::Base
has_many :events
def last_event
events.last || Event.new
end
def place
self.last_event.place
end
end
2.0.0p247 :001 > d = Device.new
=> #<Device id: nil, name: nil, created_at: nil, updated_at: nil>
2.0.0p247 :002 > d.place
=> nil
2.0.0p247 :003 > d.last_event
=> #<Event id: nil, device_id: nil, created_at: nil, updated_at: nil, place: nil>
The idea is that if a method always returns an object of the expected type, you never have to worry about subsequent calls encountering a nil object. Of course, this could have other implications - such as the need to determine if you have a valid object or a new one, but this can be checked later with:
2.0.0p247 :005 > d.last_event.new_record?
=> true
In that case you can use delegates
delegate :last, to: events, allow_nil: true, prefix: :event
delegate :place, to: event_last, allow_nil: true

Building associations in a before-filter in rails4

I am migrating an app from rails3.2.13 to rails4.0.0-rc1. I am having the following code:
class Foo < ActiveRecord::Base
has_many :bars
before_create :build_bars
private
def build_bars
self.bars.build({name: 'Bar 1'})
self.bars.build({name: 'Bar 2'})
end
end
The code above worked in rails3, but creates empty records in rails4. Some try & error in the console revealed that, indeed, attributes are not assigned.
f = Foo.new
f.bars.build({name: 'Bar'})
=> #<Bar id: nil, name: nil>
What's the proper way to build associations and have them being saved together with its parent record?
i think that #Mischa is right. i've been migrating my app over to rails4 and it works:
user.authorizations.build provider: "bla"
=> #<Authorization id: nil, provider: "bla", uid: nil, user_id: 1, created_at: nil, updated_at: nil>
you can have a look at the changes i did: https://github.com/phoet/on_ruby/pull/83/files#L23L59
most probably it's removing:
# Mass assignment settings
config.active_record.whitelist_attributes = true

Parameters not saving properly (Rails)

I have a model Messages, for which I have a recipient_list which saves as a string. For whatever reason on save, all of my parameters other than the recipient_list are being saved, with only the recipient_list being left out. I'm stumped as to what the cause for this may be.
Model:
class Message < ActiveRecord::Base
attr_accessible :content, :sender_id, :recipient_list
attr_reader :recipient_list #necessary for jquery-token-input
belongs_to :sender, class_name: "User"
validates :content, presence: true
validates :sender_id, presence: true
validates :recipient_list, presence: true
def recipient_list=(recipient) #jquery-token-input
self.recipient_ids = recipients.split(",")
end
end
Controller:
def create
#message = current_user.sent_messages.build(params[:message])
if #message.save
flash[:success] = "Message Sent."
redirect_to '/users/'+current_user.id.to_s+'/messages'
else
redirect_to '/users/'+current_user.id.to_s+'/messages'
end
end
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"WlStV4ogguSX72vrZp10zJbucS5MTL1pT1DLt06qjcw=",
"message"=>{"recipient_list"=>"1,2",
"content"=>"foobar123",
"sender_id"=>"1"},
"commit"=>"Send"}
Result:
#<Message id: 32, content: "foobar123", sender_id: 1, recipient_list: "", created_at: "2012-08-22 19:38:44", updated_at: "2012-08-22 19:38:44">]
What might be the problem that is keeping the recipient_list from being saved in this case?
Edit:
Par Ylan's note I set out to see why it was working despite the difference in variable name.
upon messing with it, I realized that it actually was only working that way if i made recipient -> recipients or the reverse the it would stop working.
Fiddled with it, and based on Nash's suggestion came up with the following:
def recipient_list=(ids)
recipient_list = ids.split(",")
super(recipient_list)
end
#<Message id: 42, content: "foobar123", sender_id: 1, recipient_list: "---\n- '1'\n", created_at: "2012-08-22 21:58:46", updated_at: "2012-08-22 21:58:46">]
So now the recipient_list is being saved, I just have to figure out how to remove all the unecessary garble and get just the '1' lol. Any further suggestions?
Edit #2:
After adding
serialize :recipient_list, Array
#<Message id: 43, content: "foobar123", sender_id: 1, recipient_list: ["1", "2"], created_at: "2012-08-22 22:10:46", updated_at: "2012-08-22 22:10:46">]
is the new out put which is what i was going for. We worked together on this one. Thanks you two.
looks like you should call super method in your overriden writer:
def recipient_list=(recipients) #jquery-token-input
self.recipient_ids = recipients.split(",")
super(recipients)
end
or something similar depends on your code.
I believe you have a typo in your writter method. You are passing an argument named recipient, but call recipients.split(","). Change either one and you should be set.

How to use a dynamically chosen class in a module

I'm fairly sure that's a useless title... sorry.
I want to be able to pass in a Class to a method, and then use that class. Here's an easy, working, example:
def my_method(klass)
klass.new
end
Using that:
>> my_method(Product)
=> #<Product id:nil, created_at: nil, updated_at: nil, price: nil>
>> my_method(Order)
=> #<Order id:nil, created_at: nil, updated_at: nil, total_value: nil>
What doesn't work is trying to use the klass variable on a module:
>> ShopifyAPI::klass.first
=> NoMethodError: undefined method `klass' for ShopifyAPI:Module
Am I attempting an impossible task? Can anyone shed some light on this?
Cheers
First off, I don't think this is impossible.
Surely, there is no klass method defined for modules <- this is true because ShopifyAPI.methods.include? "klass" # => false
However, classes are constants in modules. And modules have a constants method that you may use to retrieve classes. The problem with this is method is that is also retrieves constants in the modules that are not classes.
I came up with this workaround for your problem
# get all the classes in the module
klasses = ShopifyAPI.constants.select do |klass|
ShopifyAPI.const_get(klass).class == Class
end
# get the first class in that list
klasses.first
you could also use module_eval:
ShopifyAPI.module_eval {klass}.first
Hope I got your question right :)
irb(main):001:0> module ShopifyAPI
irb(main):002:1> class Something
irb(main):003:2> end
irb(main):004:1> end
=> nil
irb(main):005:0> klass = ShopifyAPI::Something
=> ShopifyAPI::Something
irb(main):006:0> ShopifyAPI::klass
NoMethodError: undefined method `klass' for ShopifyAPI:Module
from (irb):6
from C:/Ruby192/bin/irb:12:in `<main>
irb(main):007:0> ShopifyAPI.module_eval {klass}
=> ShopifyAPI::Something
irb(main):008:0>

Rails Single table inheritance problem

I'm trying to setup single table inheritance in my Rails app for a User model and its subclasses Member, Subscriber, and Staff.
I have a model file for each: user.rb, member.rb, etc
The user model is defined: class User < ActiveRecord::Base; end;
I subclassed the other models as such: class Member < User; end; and so on.
In my users table I have all the fields every class needs plus the type field. Now when I go to the console and try to create a new instance of say member or subscriber i get the following error:
TypeError: can't dup NilClass
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'dup'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'scoped_methods'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2188:in 'current_scoped_methods'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2171:in 'scoped?'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'send'
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'initialize'
from (irb):6:in 'new'
from (irb):6
Rails know the subclasses models are there because in the console when I simply call Member or Subscriber, i get the class definition returned.
I've read the simple documentation, but I must be missing something?
I tried on my side starting from a scratch application and it works
Here is my User model (User.rb)
class User < ActiveRecord::Base
end
My member model (Member.rb)
class Member < User
end
I have one migration file to create my users table which contains:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.timestamps
end
end
def self.down
drop_table :users
end
end
Now launching the console:
➜ ./script/console
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, created_at: nil, updated_at: nil>
>> m.name="hop"
=> "hop"
>> m.save
=> true
However I did not manage to reproduce your error :(
Do you have a type column of type varchar (string in ruby)? Try the following commands (in a new rails project)
class Member < User
end
C:\projects\test\sti>ruby script\generate model user name:string type:string membertype:string
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/user.rb
create test/unit/user_test.rb
create test/fixtures/users.yml
create db/migrate
create db/migrate/20091019051506_create_users.rb
C:\projects\test\sti>rake db:migrate
(in C:/projects/test/sti)
== CreateUsers: migrating ====================================================
-- create_table(:users)
-> 0.0000s
== CreateUsers: migrated (0.0000s) ===========================================
C:\projects\test\sti>ruby script\console
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, type: nil, membertype: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, type: "Member", membertype: nil, created_at: nil, updated_at: nil>
>> m.name = 'fred'
=> "fred"
>> m.save
=> true
>> u.name = 'rader'
=> "rader"
>> u.save
=> true
>> User.find :all
=> [#<Member id: 1, name: "fred", type: "Member", membertype: nil, created_at: "2009-10-19 05:17:11", updated_at: "2009-10-19 05:17:11">, #<User id: 2, name: "rader", type: nil, membertype: nil, created_at: "2009-10-19 05:17:24", updated_at: "2009-10-19 05:17:24">]
>>
Check this page, there are more than few solutions to this problem (even in comments).
http://strd6.com/2009/04/cant-dup-nilclass-maybe-try-unloadable/
I'm thinking that the problem is in one of your model definitions because of the stack trace you show. If you still are having a problem, pastie your code, and i'm sure you'll get a good answer.
I hade exactly this problem, after I extracted some functionality to a plugin.
But i my case it worked from the console, so i made sure id reloaded, with this line in init.rb
ActiveSupport::Dependencies.load_once_paths.delete(
File.expand_path(File.dirname(__FILE__))+'/app/models')
I ran into something similar a while back and this website helped:
http://www.dansketcher.com/2009/05/11/cant-dup-nilclass/
class User < ActiveRecord::Base
unloadable
...
end
Not sure why this occurs as I could not track down anything abnormal. I do believe it was a STI situation though.

Resources