Rails3 create method issue - ruby-on-rails

ruby-1.9.2-p0 > Subscription
=> Subscription(id: integer, email: string, tuan: boolean, send: boolean, created_at: datetime, updated_at: datetime)
ruby-1.9.2-p0 > Subscription.create("email"=>"dd")
ArgumentError: wrong number of arguments (2 for 0)
from /home/mlzboy/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.1/lib/active_record/attribute_methods/read.rb:69:in `send'
from /home/mlzboy/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.1/lib/active_record/base.rb:1548:in `block in attributes='
from /home/mlzboy/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.1/lib/active_record/base.rb:1544:in `each'
from /home/mlzboy/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.1/lib/active_record/base.rb:1544:in `attributes='
from /home/mlzboy/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.1/lib/active_record/base.rb:1411:in `initialize'
I used the above code. I want to use the create method to persist a record to db,
but it throws an error. I am new to rails3. I have checked my syntax, didn't find any error. Am I missing something?

I have figured it out by myself. In subscription model, I used a send column.
Send may be a keyword of rails so it threw an error. After I changed it to some other word e.g. 'subscribe', then it works fine.
(I have encounted this issue when used a column named "type" too)

Did you override your initialize in your Subscription model?

Related

money-rails, Money#== supports only zero numerics

I'm using the money-rails gem in my Rails application. It have worked perfectly until now, but I've recently started getting the following error:
Money#== supports only zero numerics
I'm not really sure what caused this or how to solve it. I have recently run bundle update so I guess that something have been updated. My gemfile looks like this:
gem 'money-rails', '~>1'
gem 'eu_central_bank', "~>1.3.0"
My implementation looks like this:
# model
monetize :price_in_cents
# fetch / converting currencies
eu_bank = EuCentralBank.new
Money.default_bank = eu_bank
eu_bank.update_rates
converted_price = eu_bank.exchange_with(Money.new(price_to_convert * 100, from_currency), to_currency)
This have as I mentioned worked before, so I'm not sure what is breaking it.
Any ideas?
Update
To test I tried with the following.
money = Money.new(100, from_currency)
Then I got the same error as before. But if I tried:
money = Money.new(0, from_currency)
It seems to work. I find that a bit strange.
Update
Here is the backtrace from when I try to save the record:
["/Users/[user]/.rvm/gems/ruby-2.5.1/gems/money-6.11.3/lib/money/money/arithmetic.rb:70:in =='", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/numericality.rb:22:in!='", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/numericality.rb:22:in validate_each'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:150:inblock in validate'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:147:in each'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validator.rb:147:invalidate'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:413:in block in make_lambda'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:197:inblock (2 levels) in halting'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:601:in block (2 levels) in default_terminator'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:600:incatch'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:600:in block in default_terminator'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:198:inblock in halting'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:in block in invoke_before'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:ineach'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:507:in invoke_before'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:130:inrun_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:827:in _run_validate_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations.rb:405:inrun_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/callbacks.rb:114:in block in run_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:97:inrun_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:827:in _run_validation_callbacks'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations/callbacks.rb:114:inrun_validations!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activemodel-5.1.6/lib/active_model/validations.rb:335:in valid?'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:65:invalid?'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:82:in perform_validations'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/validations.rb:50:insave!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/attribute_methods/dirty.rb:43:in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:313:inblock in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:384:in block in with_transaction_returning_status'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/database_statements.rb:235:inblock in transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/transaction.rb:194:in block in within_new_transaction'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/monitor.rb:226:inmon_synchronize'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/transaction.rb:191:in within_new_transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/connection_adapters/abstract/database_statements.rb:235:intransaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:210:in transaction'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:381:inwith_transaction_returning_status'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/transactions.rb:313:in save!'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activerecord-5.1.6/lib/active_record/suppressor.rb:46:insave!'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:245:in block in set_supported_currencys_for_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:240:ineach'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:240:in set_supported_currencys_for_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:224:inset_up_product_variant'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:208:in match_product_variant_to_product'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:84:inblock in get_products_from_api_data'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:75:in map'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:75:inget_products_from_api_data'", "/Users/[user]/Documents/Development/wondery/[appname]/lib/importers/bts_wholesaler_importer.rb:25:in import'", "(irb):2:inirb_binding'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:in eval'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/workspace.rb:85:inevaluate'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/context.rb:380:in evaluate'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:491:inblock (2 levels) in eval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:623:in signal_status'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:488:inblock in eval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:246:in block (2 levels) in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:232:inloop'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:232:in block in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:231:incatch'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb/ruby-lex.rb:231:in each_top_level_statement'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:487:ineval_input'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:428:in block in run'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:427:incatch'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:427:in run'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/irb.rb:383:instart'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:62:in start'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:17:instart'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands/console/console_command.rb:97:in perform'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor/command.rb:27:inrun'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor/invocation.rb:126:in invoke_command'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/thor-0.20.0/lib/thor.rb:387:indispatch'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/command/base.rb:63:in perform'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/command.rb:44:ininvoke'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/railties-5.1.6/lib/rails/commands.rb:16:in <top (required)>'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:inrequire'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in block in require'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:inload_dependency'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:292:in require'", "/Users/[user]/Documents/Development/wondery/[appname]/bin/rails:9:in'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:in load'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:inblock in load'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:258:in load_dependency'", "/Users/[user]/.rvm/gems/ruby-2.5.1/gems/activesupport-5.1.6/lib/active_support/dependencies.rb:286:inload'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in require'", "/Users/[user]/.rvm/rubies/ruby-2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:inrequire'", "-e:1:in `'"]
The error comes from a numericality validation on your model.
Money gem does not allow to compare a money object with a Number, unless thee number is zero. Otherwise it expects you to compare Money with Money.
In irb you can try:
```ruby
2.5.1 :006 > Money.new(1000, "USD") != Money.new(1000, "USD")
=> false
2.5.1 :007 > Money.new(1000, "USD") != 1000
Traceback (most recent call last):
4: from /Users/andi/.rvm/rubies/ruby-2.5.1/bin/irb:11:in `<main>'
3: from (irb):7
2: from (irb):7:in `!='
1: from /Users/andi/.rvm/gems/ruby-2.5.1/gems/money-6.12.0/lib/money/money/arithmetic.rb:70:in `=='
ArgumentError (Money#== supports only zero numerics)
2.5.1 :008 > Money.new(1000, "USD") != 0
=> true
```
I believe that this error makes sense, as you can't really compare an arbitrary number with an amount of money in a given currency.
The money-rails gem again comes with it's own validators:
https://github.com/RubyMoney/money-rails#numericality-validation-options
Your backtrace shows that you are using the rails numericality validator instead.
You might also come across this error when you are writing specs:
expect(order.subtotal).to eq 123.45
# ArgumentError:
# Money#== supports only zero numerics
expect(order.subtotal).to eq Money.new(12345)
# works!
Money Rails automatically adds "_cents" to the attribute you are monetizing. Then it creates an instance of that model.price which includes
<Money fractional:1500 currency:DKK>
Hence, you cannot do model.price + 10 as it would cause the error you are getting.
You may therefore want to monetize price_to_convert, or any other value you are working with so that you can sum them up, etc.
Create a new migration file e.g.
rails g migration AddMoneytizeToOrders
change migration file so that it reads as follow (change column/attribute to your values)
class AddMonetizeToOrder < ActiveRecord::Migration[6.0]
def change
add_monetize :orders, :price_to_convert, currency: { present: false }
end
end
In your model you must include
monetize :price_to_convert_cents
then you can work with e.g.(rails c) Order.last.price_to_convert + Model.last.price, etc.
Please note that you cannot use self.[:price_to_convert] as money rails wouldn't understand it and you would get the error
money rails ActiveModel::MissingAttributeError (can't write unknown attribute...
Therefore use self.price_to_convert instead

Active Record acting weird

Question am I doing something wrong with the following code?
Controller Test
irb(main):003:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.8ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation]'
=> #<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
The above works and retrieves my row that I queried for.
but below I tried to get the data for x.owner_id from the above and it fails(which clearly owner_id is a column in the returned query above)
irb(main):005:0> x.owner_id
NoMethodError: undefined method `owner_id' for #<Notations::ActiveRecord_Relation:0x007fb83cecf288>
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:136:in `method_missing'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.8/lib/active_record/relation/delegation.rb:99:in `method_missing'
from (irb):5
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:110:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/console.rb:9:in `start'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:68:in `console'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/railties-4.2.8/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
I found the problem. The column names of the db were uppercase, so:
y = x.owner_id # failure
y = x.OWNER_ID # success
irb(main):004:0> x.OWNER_ID
=> "00003"
Solution:
Using an initializer to use lowercase schema reflection:
ActiveRecord::ConnectionAdapters::SQLServerAdapter.lowercase_schema_reflection = true
So now:
x = Notations.all.first
irb(main):002:0> x = Notations.all.first
/Users/programmer/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-sqlserver-adapter-4.2.18/lib/active_record/connection_adapters/sqlserver/database_statements.rb:354: warning: :timezone option must be :utc or :local - defaulting to :local
Notations Load (1.9ms) EXEC sp_executesql N'SELECT [notation].* FROM [notation] ORDER BY [notation].[owner_id] ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'
irb(main):003:0> x.owner_id
=> "00003"
irb(main):004:0>
As you can see above adding the initializer worked it changed the columns to lower case. I agree with having my columns lower case in the first place. However I am unable to change them due to this DB is used with my company's ERP system
You are calling the attribute on ActiveRecord::Relation whereas you must be calling it on Notations instance
x = Notations.all
#<ActiveRecord::Relation [#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">]
notation = x.first
#<Notations ROWID: 1, TYPE: "Q ", OWNER_ID: "00003", CREATE_DATE: "2017-05-31 21:32:06", NOTE: "\r\x00\n\x00R\x00e\x00f\x00e\x00r\x00e\x00n\x00c\x00e\x00 \x00R\x00F\x00Q\x00 \x001\x007\x005\x005\x002\x00-\x000\x001\x000\x00...">
notation.owner_id
#=> "00003"
NOTE: Whereas the above code must be working for you I will suggest few changes as per the ruby standard
Model name must be singular Notation instead of Notations
column names must be in lowercase owner_id instead of OWNER_ID

factory_girl does not set model attribute

factory_girl is not setting the url attribute on the model correctly. I looked to see if there are reserved words, but I found nothing.
factory :attachment do
association :attachable, factory: :upload
url "some/path"
description "Some important file"
end
I get this failure. Notice url: nil
1) Attachment should be valid
Failure/Error: it { should be_valid }
expected #<Attachment id: 1048, attachable_id: 1047, attachable_type: "Upload", name: nil, url: nil, created_at: nil, updated_at: nil, description: "Some important file"> to be valid, but got errors: Url can't be empty
# ./spec/models/attachment_spec.rb:14:in `block (2 levels) in <top (required)>'
I ran factory_girl in the console and got the same result with FactorGirl.attributes_for :attachment
Running Rails 4 with FactoryGirl 4.2.1.
I was having this same issue and after hours of banging my head on the desk I decided to stop and restart my Spring server. It started working like magic.
Before restarting my Spring server I was able to set attributes using create :object, new_field: true but just using create :object wouldn't work, even if I had new_field true in my factories.rb file.
Late to the party but I had the same problem. I had added all my attributes after the initial migration, and it turned out I was using attr_accessor instead of attr_accessible in my model.

Rails 3 Occasional Routing Error

I'm running Rails 3.1.1 and getting an odd bug. In development (haven't yet tried pushing to production with it) I'm occasionally getting routing errors in my controller or in my mailer template when it tries to generate a url for a newly created record. This happens even though the record is created successfully and appears to have nothing to do with the record properties (I can recreate a record with the exact same params right after and not get the error, it seems totally random when it happens).
It seems to happen maybe one in 10 times, though I can't say I ever saw an incident of it happening before I added the mailer action.
There's one more potentially complicating factor: I'm using an encryption method to obfuscate the record's id in its URL, but this is otherwise working without a hitch. To do this I adapted the method discussed here
It seems to me like the URL's not generated in time for the link_to call some of the time... But that doesn't make much sense to me. I didn't think race conditions were something I needed to worry about here.
Here are my error logs when this happens in the controller (when the params don't call for an email to be generated):
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"watch_lists", :id=>#<WatchList id: 195, title: "sfdsfd", created_at: "2012-03-19 05:18:46", updated_at: "2012-03-19 05:18:46", public_list: false>}):
app/controllers/watch_lists_controller.rb:72:in `block (2 levels) in create'
app/controllers/watch_lists_controller.rb:56:in `create'
And here's when it happens in the mailer template (when the params do call for an email to be generated before the render command):
Rendered watch_list_mailer/share_notification.html.erb (3.2ms)
Completed 500 Internal Server Error in 113ms
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"watch_lists", :id=>#<WatchList id: 210, title: "sdggsgsg", created_at: "2012-03-19 05:47:17", updated_at: "2012-03-19 05:47:17", public_list: true>}):
20: <% end %>
21: <% end %><br>
22: <br>
23: Here's a link to your WatchList: <%= link_to #wl.title, watch_list_url(#wl) %><br>
24: <br>
25: Enjoy!
26: </p>
app/views/watch_list_mailer/share_notification.html.erb:23:in `_app_views_watch_list_mailer_share_notification_html_erb___1391186431365383285_70156615518000'
app/mailers/watch_list_mailer.rb:12:in `share_notification'
app/controllers/watch_lists_controller.rb:124:in `share_notification'
app/controllers/watch_lists_controller.rb:68:in `block (2 levels) in create'
app/controllers/watch_lists_controller.rb:63:in `each'
app/controllers/watch_lists_controller.rb:63:in `block in create'
app/controllers/watch_lists_controller.rb:56:in `create'
EDIT: Upon further testing, this appears to happen regardless of whether I include the mail task. It seems most likely spurred by the obfuscation of the links. It's possible that the encoding of the links has something to do with it (I had to make sure to URI-escape them to prevent slashes in the wrong places elsewhere in my code). I'll investigate this futher and report back.
It was a problem with the id encryption creating invalid links occasionally and me failing to account for that in early enough in the process.
In lib/obfuscate.rb
def uri_encrypt(value)
URI.escape(self.encrypt(value), Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
end
In my model
def to_param
uri_encrypt(id)
end

to_xml Doesn't Work on Objects Returned Through Rails ActiveRecord habtm Reference

I have two rails active record classes, School and Instructor linked by a has_and_belongs_to_many relationship.
I need to query my instructors_controller for instructors for a particular school and return an xml format response. Therefore, in the index method I have this code fragment:
school = School.find(params[:school_id])
#instructors = school.instructors
and later:
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #instructors }
format.json { render :json => #instructors }
end
But it doesn't work. Look at this intriguing but baffling sequence:
ruby-1.9.2-p180 :023 > Instructor.all.first
=> #<Instructor id: 1, name: "Mrs. Smith", instructor_type_id: 1, created_at: "2011-07-24 18:19:40", updated_at: "2011-07-24 18:19:40">
ruby-1.9.2-p180 :026 > Instructor.all.first.class
=> Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime)
ruby-1.9.2-p180 :024 > School.first.instructors.first
=> #<Instructor id: 1, name: "Mrs. Smith", instructor_type_id: 1, created_at: "2011-07-24 18:19:40", updated_at: "2011-07-24 18:19:40">
ruby-1.9.2-p180 :025 > School.first.instructors.first.class
=> Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime)
ruby-1.9.2-p180 :021 > Instructor.all.first.to_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<instructor>\n <created-at type=\"datetime\">2011-07-24T18:19:40Z</created-at>\n <id type=\"integer\">1</id>\n <instructor-type-id type=\"integer\">1</instructor-type-id>\n <name>Mrs. Smith</name>\n <updated-at type=\"datetime\">2011-07-24T18:19:40Z</updated-at>\n</instructor>\n"
Now for the punchline:
ruby-1.9.2-p180 :019 > School.first.instructors.first.to_xml
NoMethodError: undefined method `type' for nil:NilClass
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activesupport-3.0.9/lib/active_support/whiny_nil.rb:48:in `method_missing'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:230:in `compute_type'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:22:in `initialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `new'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `block in serializable_attributes'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `each'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `map'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `serializable_attributes'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:116:in `add_attributes_and_methods'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:103:in `block in serialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `call'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `_nested_structures'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:58:in `method_missing'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:31:in `tag!'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:102:in `serialize'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:175:in `to_xml'
from (irb):19
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.2-p180#blueprint/gems/railties-3.0.9/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'ruby-1.9.2-p180 :020 > Instructor.all.first.to_xml
What's going on here ?
Edit: Well, switching from xml to json solved the problem, (to_json does not exhibit the same strangeness as to_xml here), although I would still like to know the explanation for the above behavior.
Also, as I am relatively new to Rails, is there a better way to do what I want to do here ?
to_xml() tries to define a type attribute for each model attribute. For example, a User model with an age (INT) attribute will have: <age type="integer">42</age>. This type information is not encoded in JSON, which is why to_json() works for you. Add this method to your Instructor model:
def to_xml(options = {})
to_xml_opts = {:skip_types => true} # no type information, not such a great idea!
to_xml_opts.merge!(options.slice(:builder, :skip_instruct))
# a builder instance is provided when to_xml is called on a collection of instructors,
# in which case you would not want to have <?xml ...?> added to each item
to_xml_opts[:root] ||= "instructor"
self.attributes.to_xml(to_xml_opts)
end
This would however make your XML devoid of any type information - not good if someone has a JAVA REST client. A better strategy would be to filter self.attributes.slice(*keys).to_xml(to_xml_opts) where keys is an array of model attributes you want in the XML.

Resources