Rails ActiveRecard validation fail - ruby-on-rails-3

I'm having some trouble saving a model
class AmazonMovie < ActiveRecord::Base
attr_accessible :asin_buy, :asin_rent, :movie_id, :on_prime, :on_prime_prev, :price_buy, :price_buy_prev, :price_rent, :price_rent_prev, :url, :updated_at, :created_at
belongs_to :movie
has_many :amazon_movie_changes, :dependent => :destroy
validates :movie_id, presence: true, uniqueness: true
AWS_QPS_THRESHOLD = 1.0
before_create :init
def init
self.on_prime_prev = false
end
def update_changes
...
There's another class
class AmazonMovieChange < ActiveRecord::Base
attr_accessible :amazon_movie_id, :buy_change, :movie_id, :on_prime, :on_prime_prev, :price_buy, :price_buy_prev, :price_rent, :price_rent_prev, :prime_change, :rent_change
belongs_to :movie
belongs_to :amazon_movie
validates_presence_of :movie_id, :amazon_movie_id
....
When I created a model like the following:
=> #<AmazonMovie id: nil, movie_id: 16918, asin_buy: "B00FSTCUGA", price_buy: 7.99, price_buy_prev: nil, asin_rent: "B00FST7SX0", price_rent: 3.99, price_rent_prev: nil, on_prime: false, on_prime_prev: false, url: "http://www.amazon.com/Strongman-Stanless-Steel/dp/B...", created_at: nil, updated_at: nil>
I'm getting the following save failure:
ActiveRecord::RecordInvalid: Validation failed: Amazon movie changes is invalid
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/validations.rb:56:in `save!'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/transactions.rb:246:in `block in save!'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/transactions.rb:295:in `block in with_transaction_returning_status'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/transactions.rb:208:in `transaction'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/transactions.rb:293:in `with_transaction_returning_status'
from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.8/lib/active_record/transactions.rb:246:in `save!'
from (irb):145
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.8/lib/rails/commands/console.rb:47:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.8/lib/rails/commands/console.rb:8:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.8/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
UPDATE:
I realized by removing the before_create :init this model saves without errors. My original intent was to default this field as false instead of NULL. Is there something wrong in my syntax? Or this is not the right way to default a field?

Related

update with has_many through SQL Error

Models:
class User < ActiveRecord::Base
end
class Game::Session < ActiveRecord::Base
has_many :session_users, foreign_key: 'game_session_id'
has_many :users, through: :session_users
end
class Game::SessionUser < ActiveRecord::Base
belongs_to :user
belongs_to :session, foreign_key: 'game_session_id'
end
Tables:
create_table :users do |t|
...
end
create_table :game_sessions do |t|
...
end
create_table :game_session_users, :id => false do |t|
t.references :user, null: false
t.references :game_session, null: false
t.string :state, null: false
end
I have no problem creating and querying Game::SessionUser models, but I get SQL error when trying to update them.
for example:
Game::Session.first.session_users.first.update(state: 'winner')
results in this:
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: zero-length delimited identifier at or near """"
LINE 1: ...sers" SET "state" = $1 WHERE "game_session_users"."" IS NULL
^
: UPDATE "game_session_users" SET "state" = $1 WHERE "game_session_users"."" IS NULL
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:811:in `prepare'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:811:in `prepare_statement'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:772:in `exec_cache'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:160:in `block in exec_delete'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:425:in `block in log'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activesupport-4.0.0/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract_adapter.rb:420:in `log'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:158:in `exec_delete'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:102:in `update'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/query_cache.rb:14:in `update'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/persistence.rb:489:in `update_record'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/locking/optimistic.rb:70:in `update_record'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/attribute_methods/dirty.rb:74:in `update_record'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/callbacks.rb:307:in `block in update_record'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:373:in `_run__995479063__update__callbacks'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:80:in `run_callbacks'
... 16 levels...
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/transactions.rb:281:in `rollback_active_record_state!'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/transactions.rb:269:in `save'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/persistence.rb:230:in `block in update'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/transactions.rb:326:in `block in with_transaction_returning_status'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `block in transaction'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:210:in `within_new_transaction'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `transaction'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/transactions.rb:209:in `transaction'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/transactions.rb:323:in `with_transaction_returning_status'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/persistence.rb:228:in `update'
from (irb):1
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
from C:/Ruby200/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
The db is PostgreSQL, thanks.
I fixed the issue by using this composite keys gem: http://compositekeys.rubyforge.org/ and make sure to use version 6.0.0.
You'll just need to specify the composite primary key in your model:
class Game::SessionUser < ActiveRecord::Base
belongs_to :user
belongs_to :session, foreign_key: 'game_session_id'
self.primary_keys = :user_id, :game_session_id
end

Getting an error with custom validation in a Rails 3 ActiveModel

I'm trying to use the Date Validator Gem but I am running into an error and I'm not sure if it's because the model isn't Active Record or not (I've seen people suggest that validation is a bit funky in ActiveModel when not in ActiveRecord).
I am using Ruby 1.9.2 & Rails 3.0.7. I've attached both the class and the error below.
Thanks in advance for any help!
Class
require 'ice_cube'
require 'active_support'
require 'active_support/time_with_zone'
require 'ostruct'
require 'tzinfo'
require 'active_model'
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
class Schedule
attr_accessor :yaml, :repeat, :interval, :interval_unit, :start_time, :start_date, :end_date, :end_time, :ends, :on, :after, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
validates_presence_of :repeat, :start_date, :start_time, :end_date, :end_time, :ends
validates_presence_of :interval, :interval_unit, :if => :ends_never?
validates_presence_of :on, :if => :ends_on_date?
validates_numericality_of :after, :greater_than => 0, :if => :ends_after_recurrences?
validates :start_date, :date => { :after => Time.now }
validates :end_date, :date => { :after => :start_date }
validates :on, :date => { :after => :end_date }
def initialize(attributes = {})
end
def persisted?
false
end
private
def parse_schedule
if :repeat == 0
get_repeatable
end
end
def parse_yaml
end
def ends_on_date?
return :ends == "on"
end
def ends_never?
return :ends == "never"
end
def ends_after_recurrences?
return :ends == "after"
end
end
Error from Rails Console
ruby-1.9.2-p180 :001 > s = Schedule.new
NoMethodError: undefined method `new' for DateValidator:Module
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/with.rb:70:in `block in validates_with'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/with.rb:69:in `each'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/with.rb:69:in `validates_with'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/validates.rb:90:in `block in validates'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/validates.rb:83:in `each'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activemodel-3.0.7/lib/active_model/validations/validates.rb:83:in `validates'
from /Users/chance/Sites/EatingNow/app/models/schedule.rb:16:in `<class:Schedule>'
from /Users/chance/Sites/EatingNow/app/models/schedule.rb:10:in `<top (required)>'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:454:in `load'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:454:in `block in load_file'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:596:in `new_constants_in'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:453:in `load_file'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:340:in `require_or_load'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:491:in `load_missing_constant'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:183:in `block in const_missing'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:181:in `each'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:181:in `const_missing'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.5.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/rspec-expectations-2.5.0/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing'
from (irb):1
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands/console.rb:44:in `start'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands/console.rb:8:in `start'
from /Users/chance/.rvm/gems/ruby-1.9.2-p180/gems/railties-3.0.7/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
You have included/extended the top-level namespace. Make sure the includes/extends are IN the class.
class Schedule
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming

Rails habtm grief am I dumb or rails bug? (desperate ; )

Greetings all,
I'm having a weird problem with a habtm relationship and honestly I'm beginning to think I may have stumbled upon some weird bug in rails 3. Surely I'm crazy though. I've been beating my head against the wall on this for 3 days, have googled everything under the sun I can think of and still can't come up with an answer.
Ok, the situation:
I'm creating a Rails app to replace both a Java app and a PHP app (java application and php front-end). This is going to be a phased operation with the first phase being the Rails application takes over registration and billing. In order to do this, the Rails application must create data in the databases for the Java and PHP apps. The Rails application itself is using Devise for authentication.
In database.yml I have my standard 3 databases defined and also a connection defined for the Java apps database.
Here are pieces of the model definitions for the external object (I'm just creating regular rails models to talk to the external databases):
class Pushbroom::UserAccount < ActiveRecord::Base
require 'digest/md5'
require 'base64'
establish_connection :pushbroom
set_table_name :user_account
set_primary_key :id
has_and_belongs_to_many :user_roles, :join_table => 'pb_prod.users_roles', :class_name => 'Pushbroom::UserRole', :foreign_key => 'user_account_id', :association_foreign_key => 'user_role_id'
belongs_to :user, :dependent => :destroy
attr_accessible :user_roles, :admin_notes, :enabled, :username, :password_hash, :prefStore, :accepted_tos, :do_not_contact
end
class Pushbroom::UserRole < ActiveRecord::Base
establish_connection :pushbroom
set_table_name :user_role
set_primary_key :id
has_and_belongs_to_many :user_accounts, :join_table => 'pb_prod.users_roles', :class_name => 'Pushbroom::UserAccount', :foreign_key => 'user_role_id', :association_foreign_key => 'user_account_id'
end
And finally my Rails application user object:
class User < ActiveRecord::Base
after_create :send_welcome_email
before_save :create_pushbroom_user_data
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :pb_user_account, :class_name => "Pushbroom::UserAccount", :foreign_key => "pb_user_account_id", :dependent => :destroy, :autosave => true
# Setup accessible (or protected) attributes for your model
attr_accessible :first_name, :last_name, :username, :dob, :email, :password, :password_confirmation, :remember_me
validates_presence_of :first_name, :last_name, :username, :dob
validates_date :dob, :on_or_after => lambda { 100.years.ago }, :on_or_after_message => "must be on or after #{100.years.ago.strftime('%m-%d-%Y')}"
validates_date :dob, :on_or_before => lambda { 13.years.ago }, :on_or_before_message => "must be on or before #{13.years.ago.strftime('%m-%d-%Y')}"
def create_pushbroom_user_data
pb_user = create_pushbroom_user
pb_user_account = create_pushbroom_user_account(pb_user)
pb_user_account.user_roles << Pushbroom::UserRole.find_by_name('user')
self.pb_user_account = pb_user_account
end
def create_pushbroom_user
pb_user = Pushbroom::User.new
pb_user.attributes = self.attributes.slice(
"email",
"first_name",
"last_name",
"dob")
pb_user
end
def create_pushbroom_user_account(pb_user)
pb_user_account = Pushbroom::UserAccount.new
pb_user_account.enabled = true
pb_user_account.password_hash = Pushbroom::UserAccount.create_password_digest(#plaintext_password, self.username)
pb_user_account.username = self.username
pb_user_account.user = pb_user
pb_user_account
end
Seems like it should be pretty vanilla. The ONLY weirdness here is that they aren't in the native rails database and one of the fields is named funny in the relations table.
So here's a rails console session where I create a rails user, call the method to create the external objects, then try to save:
ruby-1.9.2-p180 :001 > def user_fred
ruby-1.9.2-p180 :002?> {
ruby-1.9.2-p180 :003 > :first_name => "Fred",
ruby-1.9.2-p180 :004 > :last_name => "Flinstone",
ruby-1.9.2-p180 :005 > :username => "fflint",
ruby-1.9.2-p180 :006 > :dob => "1986-06-01",
ruby-1.9.2-p180 :007 > :email => "fred#mydomain.org",
ruby-1.9.2-p180 :008 > :password => "badpass"
ruby-1.9.2-p180 :009?> }
ruby-1.9.2-p180 :010?> end
=> nil
ruby-1.9.2-p180 :011 > user = User.new(user_fred)
=> #<User id: nil, email: "fred#mydomain.org", encrypted_password: "$2a$10$IiEOEoSnXIrP7VJAQYckfOVXuzm7Y5ZGo20ayLpSkHhz...", reset_password_token: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil, first_name: "Fred", last_name: "Flinstone", username: "fflint", dob: "1986-06-01", pb_user_account_id: nil>
ruby-1.9.2-p180 :012 > user.create_pushbroom_user_data
=> #<Pushbroom::UserAccount id: nil, created_by: nil, created_at: nil, updated_by: nil, updated_at: nil, admin_notes: nil, enabled: true, username: "fflint", password_hash: "blah blah", user_id: nil, prefStore: nil, accepted_tos: nil, do_not_contact: nil>
ruby-1.9.2-p180 :013 > user.pb_user_account.user_roles
=> [#<Pushbroom::UserRole id: 1, created_by: "script", created_at: "2008-11-10 12:10:44", updated_by: "script", updated_at: "2008-11-10 12:10:44", admin_notes: "", name: "user", description: "Generic User Role", conditional: false>]
ruby-1.9.2-p180 :014 > user.save!
NoMethodError: undefined method `relation' for nil:NilClass
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activesupport- 3.0.5/lib/active_support/whiny_nil.rb:48:in `method_missing'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/arel- 2.0.9/lib/arel/insert_manager.rb:22:in `insert'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/arel- 2.0.9/lib/arel/crud.rb:26:in `insert'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord- 3.0.5/lib/active_record/associations/has_and_belongs_to_many_association.rb:76:in `insert_record'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord- 3.0.5/lib/active_record/associations/association_proxy.rb:151:in `send'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:306:in `block in save_collection_association'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/associations/association_collection.rb:431:in `block in method_missing'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `block in method_missing'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `each'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/associations/association_proxy.rb:216:in `method_missing'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/associations/association_collection.rb:431:in `method_missing'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:297:in `save_collection_association'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/autosave_association.rb:163:in `block in add_autosave_association_callbacks'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activesupport-3.0.5/lib/active_support/callbacks.rb:415:in `_run_create_callbacks'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/callbacks.rb:281:in `create'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/persistence.rb:246:in `create_or_update'
... 18 levels...
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/callbacks.rb:277:in `create_or_update'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/persistence.rb:56:in `save!'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/validations.rb:49:in `save!'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/attribute_methods/dirty.rb:30:in `save!'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/transactions.rb:245:in `block in save!'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord- 3.0.5/lib/active_record/transactions.rb:292:in `block in with_transaction_returning_status'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/transactions.rb:207:in `transaction'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/transactions.rb:290:in `with_transaction_returning_status'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/activerecord-3.0.5/lib/active_record/transactions.rb:245:in `save!'
from (irb):14
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/railties-3.0.5/lib/rails/commands/console.rb:44:in `start'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/railties-3.0.5/lib/rails/commands/console.rb:8:in `start'
from /Users/gander/.rvm/gems/ruby-1.9.2-p180#sms2/gems/railties-3.0.5/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 :015 >
If I remove the role assignment, everything is just peachy (finds, saves, destroys, etc), but the second I try to save roles everything blows sky-high with this message that, frankly, I don't get. It knows its got the roles, there is no nil object that I can tell. . .and basically if I wasn't already bald I'd be pulling my hair out ; )
Any insight into this is EXTREMELY appreciated!
Gerald
P.S. Also asked here http://railsforum.com/viewtopic.php?id=43647 Will duplicate answer if found.
After beating myself silly for 4 days on this I finally found the problem: Rails (habtm) doesn't have the ability to determine the database to use for external relation tables. I also found the answer, and it doesn't even smell bad! There's a whole thread on the process here: http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/c5655d0442039ccd
The answer? has_many :through - something I'd never taken much of a look at, but it is actually a pretty nice feature (even in other circumstances).
Basically this just allows me to create a model class which represents the relationship. And since I have a model class for it I can explicitly specify the database to connect to.
For posterity sake, here's the code:
class Pushbroom::UsersRolesRelationship < ActiveRecord::Base
establish_connection :pushbroom
set_table_name :users_roles
belongs_to :user_account
belongs_to :user_role
end
class Pushbroom::UserAccount < ActiveRecord::Base
establish_connection :pushbroom
set_table_name :user_account
set_primary_key :id
has_many :users_roles_relationships
has_many :user_roles, :through => :users_roles_relationships, :source => :user_role
end
class Pushbroom::UserRole < ActiveRecord::Base
establish_connection :pushbroom
set_table_name :user_role
set_primary_key :id
has_many :users_roles_relationships
has_many :user_accounts, :through => :users_roles_relationships, :source => :user_account
end
And is used thusly:
def add_subscription_plan_roles_to_pb_user_account(pb_user_account)
roles_granted = pb_user_account.user.subscriptions.first.subscription_plan.roles_granted
pb_user_account.user_roles = roles_granted
end
Thanks a ton folks for helping me get this train moving again! All my tests are passing and it seems to be working, but if you see something wrong, please do still let me know.
Thanks!
Gerald
Try doing some manual saves of the objects created in various places, such as the create_pushbroom_user_account(pb_user) method. I have had some issues in the past when relying on the "autosave" system.

Undefined method for friendly_id implementation

This is what my Plan.rb looks like:
class Plan < ActiveRecord::Base
has_many :users
has_friendly_id :plan, :use_slug => true
end
User.rb
class User < ActiveRecord::Base
#There is other stuff in here, but I stripped it out for brevity purposes.
has_and_belongs_to_many :projects
has_many :stages
has_many :uploads
has_many :comments
has_many :assignments
has_many :roles, :through => :assignments
belongs_to :plan
end
This is the error message I am getting:
'ruby-1.9.2-p0 > Plan.create(:name => "First_Test", :storage => "100")
NoMethodError: undefined method `plan' for #<Plan:0x00000102b8a2d8>
/gemms/ruby-1.9.2-p0/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:364:in `method_missing'
/gemms/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:46:in `method_missing'
/gems/ruby-1.9.2-p0/gems/friendly_id-3.2.0/lib/friendly_id/slugged.rb:82:in `slug_text'
/gems/ruby-1.9.2-p0/gems/friendly_id-3.2.0/lib/friendly_id/active_record_adapter/slugged_model.rb:49:in `build_a_slug'
/gems/ruby-1.9.2-p0/gems/activesupport-3.0.3/lib/active_support/callbacks.rb:419:in `_run_save_callbacks'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/callbacks.rb:277:in `create_or_update'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/persistence.rb:39:in `save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/validations.rb:43:in `save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/attribute_methods/dirty.rb:21:in `save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:237:in `block (2 levels) in save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:289:in `block in with_transaction_returning_status'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:204:in `transaction'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:287:in `with_transaction_returning_status'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:237:in `block in save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:248:in `rollback_active_record_state!'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/transactions.rb:236:in `save'
/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/base.rb:498:in `create'
from (irb):3
/gems/ruby-1.9.2-p0/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
/gems/ruby-1.9.2-p0/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
/gems/ruby-1.9.2-p0/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Not sure what I am doing wrong here, but I can't create any new 'plans'.
It looks like your database doesn't have a plan column in your plans table. In addition to adding the has_friendly_id statement to your model, did you create and run a migration to add the plan field to your database?
You can also get this error (undefined method `has_friendly_id') if you have upgraded friendly_id from Version 3 to 4.
Command 'has_friendly_id' has been replaced by 'friendly_id' - see how to upgrade here:
http://rubydoc.info/github/norman/friendly_id/master/file/WhatsNew.md
Note: You'll also need to create a migration to add a new slug column to your table.

How to properly use Factory_girl and has_many 'through' models

I'm having a little difficulty groking the call back model and methodology in Factory Girl. Using this post http://robots.thoughtbot.com/post/254496652/aint-no-calla-back-girl I started giving it a go and, now I'm erroring in the spec. I am new to Rails...so I may be missing something really fundamental.
The Error is:
Failure/Error: #user = Factory(:admin_user)
undefined method 'each' for #
The Models:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable, :lockable,
:recoverable, :rememberable, :trackable, :validatable, :token_authenticatble
# Setup accessible (or protected) attributes for your model
attr_accessible :username, :email, :role_ids, :password, :password_confirmation, :remember_me
has_many :userroles
has_many :roles, :through=>:userroles
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
end
class Role < ActiveRecord::Base
attr_accessible :name
validates :name, :presence=>true,
:length=>{:minimum=>4, :maximum=>30}
has_many :userroles
has_many :users, :through=>:userroles
end
class Userrole < ActiveRecord::Base
attr_accessible :user_id, :role_id
belongs_to :user
belongs_to :role
end
The Factories:
Factory.define :user do |f|
f.email 'someone#somecompany.com'
f.username 'foo'
f.password '123456'
end
Factory.define :role do |r|
r.name 'testrole'
end
Factory.define :userrole do |ur|
ur.association(:role)
ur.userrole{|ur| ur.userrole(:user)}
end
Factory.define :admin_role, :class => 'Role' do |userrole|
userrole.role { |role| role.association(:role, :name => "Admin") }
end
Factory.define :admin_user, :parent => :user do |user|
user.after_create { |u| Factory(:admin_role, :userroles => u) }
end
Lastly the simple spec:
require File.dirname(__FILE__) + '/../spec_helper'
describe RolesController do
fixtures :all
include Devise::TestHelpers
render_views
before (:each) do
#user = Factory(:admin_user)
sign_in #user
end
it "index action should render index template" do
get :index
response.should render_template(:index)
end
end
Update: Adding Stack Trace
ruby-1.9.2-p136 :001 > u=Factory(:admin_user)
NoMethodError: undefined method `each' for #<User:0x00000004d737d8>
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/activemodel-3.0.3/lib/active_model/attribute_methods.rb:364:in `method_missing'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/activerecord-3.0.3/lib/active_record/attribute_methods.rb:46:in `method_missing'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/activerecord-3.0.3/lib/active_record/associations/association_collection.rb:352:in `replace'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/activerecord-3.0.3/lib/active_record/associations.rb:1524:in `block in collection_accessor_methods'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy/build.rb:13:in `set'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:320:in `block in run'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:320:in `each'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:320:in `run'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:270:in `create'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:301:in `default_strategy'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl.rb:20:in `Factory'
from /home/ryan/Sites/Holocron/spec/factories/users.rb:22:in `block (2 levels) in <top (required)>'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy.rb:29:in `call'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy.rb:29:in `block in run_callbacks'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy.rb:28:in `each'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy.rb:28:in `run_callbacks'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/proxy/create.rb:7:in `result'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:327:in `run'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:270:in `create'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl/factory.rb:301:in `default_strategy'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/factory_girl-1.3.2/lib/factory_girl.rb:20:in `Factory'
from (irb):1
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
from /home/ryan/.rvm/gems/ruby-1.9.2-p136#Holocron/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
I believe you've confused yourself.
You've defined Factory.define :admin_role, :class => 'Role' do |userrole| as a Role but then in your factory definition you treat it like a Userrole. (BTW, Ruby conventions use underlines – so Userrole would be UserRole/user_role.)
Also, your user.after_create { |u| Factory(:admin_role, :userroles => u) } probably ought to be: user.after_create { |u| Factory(:admin_role, :userroles => [u]) } since a Role has_many :userroles.