ActiveRecord::HasManyThroughNestedAssociationsAreReadonly Error in Rails Admin - ruby-on-rails-3

I just upgraded to Rails 3.2.10 and am getting an error message that I never used to get when updating a record via RailsAdmin.
ActiveRecord::HasManyThroughNestedAssociationsAreReadonly at /admin/vendor/12/edit
Message Cannot modify association 'Vendor#categories' because it goes through more than one other association.
This is my Vendor model:
class Vendor < ActiveRecord::Base
attr_accessible :name, :description, :banner_image, :logo_image, :intro_text, :thumb_image, :category_ids, :product_ids, :user_id, :remove_banner_image, :banner_image_cache, :remove_logo_image, :logo_image_cache
mount_uploader :banner_image, ImageUploader
mount_uploader :logo_image, ImageUploader
mount_uploader :thumb_image, ImageUploader
has_many :products, :dependent => :destroy
has_many :categories, :through => :products
belongs_to :owner, :class_name => "User",
:foreign_key => "user_id"
end
This is my Category model:
class Category < ActiveRecord::Base
attr_accessible :name, :product_ids, :category_ids
has_many :category_products do
def with_products
includes(:product)
end
end
has_many :products, :through => :category_products
end
This is my Product model:
class Product < ActiveRecord::Base
attr_accessible :name, :description, :price, :vendor_id, :image, :category_ids, :sku, :remove_image, :image_cache
mount_uploader :image, ImageUploader
belongs_to :vendor
has_many :category_products do
def with_categories
includes(:category)
end
end
has_many :categories, :through => :category_products
end
This is my CategoryProduct model:
class CategoryProduct < ActiveRecord::Base
attr_accessible :product_id, :category_id, :purchases_count
belongs_to :product
belongs_to :category
validates_uniqueness_of :product_id, :scope => :category_id
end

This happens because your association is nested, meaning (from rails source) :
A through association is nested if there would be more than one join table... which is your case here.
Apparently a workaround (I didn't test) is telling Vendor it doesn’t need to autosave the association.
has_many :categories, :through => :products, :autosave => false

You can mark the association as readonly and rails_admin will then not generate the category fields in the form for vendor:
has_many :categories, -> { readonly }, through: :products

Related

Using has_many through with nested namespaces

I have a nested model like so:
class Games::Player < ActiveRecord::Base
attr_accessible :user_id
belongs_to :user
has_many :games_extras_achievements_players, :class_name => 'Games::Extras::AchievementsPlayer'
has_many :games_extras_achievements, :class_name => 'Games::Extras::Achievement',:through=>:games_extras_achievements_players
validates :user_id,uniqueness: true
end
class Games::Extras::Achievement < ActiveRecord::Base
has_many :games_extras_achievements_players, :class_name => 'Games::Extras::AchievementsPlayer'
has_many :games_players, through: :games_extras_achievements_players, class_name: 'Games::Player'
end
class Games::Extras::AchievementsPlayer < ActiveRecord::Base
attr_accessible :games_extras_achievement_id, :games_player_id
belongs_to :games_extras_achievement, :class_name => 'Games::Extras::Achievement'
belongs_to :games_player, :class_name => 'Games::Player'
end
Objects on the join class work as expected.
However trying to get player -> achievement or vice versa gives an error:
> p.games_extras_achievements
Games::Extras::Achievement Load (0.3ms) SELECT "games_extras_achievements".* FROM "games_extras_achievements" INNER JOIN "games_extras_achievements_players" ON "games_extras_achievements"."id" = "games_extras_achievements_players"."games_extras_achievement_id" WHERE "games_extras_achievements_players"."player_id" = 1
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column games_extras_achievements_players.player_id does not exist
LINE 1: ...ents_players"."games_extras_achievement_id" WHERE "games_ext...
If I change the migration to use player_id like it is trying to find, I get an error stating that games_player_id does not exist
I seem to have fixed it.
I needed to use the non-namespaced column names and add a foreign key constraint.
class Games::Player < ActiveRecord::Base
attr_accessible :user_id
belongs_to :user
has_many :games_extras_achievements_players, :class_name => 'Games::Extras::AchievementsPlayer'
has_many :games_extras_achievements, :class_name => 'Games::Extras::Achievement',:through=>:games_extras_achievements_players
validates :user_id,uniqueness: true
end
class Games::Extras::Achievement < ActiveRecord::Base
has_many :games_extras_achievements_players, :class_name => 'Games::Extras::AchievementsPlayer'
has_many :games_players, through: :games_extras_achievements_players, class_name: 'Games::Player'
end
class Games::Extras::AchievementsPlayer < ActiveRecord::Base
attr_accessible :achievement_id, :player_id
belongs_to :games_extras_achievement, class_name:'Games::Extras::Achievement',foreign_key: :achievement_id
belongs_to :games_player, class_name: 'Games::Player',foreign_key: :player_id
end
Hopefully this will save someone some aggravation.

Ruby on Rails: SQLite3::SQLException: no such column:

SELECT "groups".* FROM "groups"
INNER JOIN "groups_interests" ON "groups"."id" = "groups_interests"."group_id"
WHERE "groups_interests"."interest_id" = 1
SQLite3::SQLException: no such column: groups_interests.interest_id: SELECT "groups".* FROM "groups" INNER JOIN "groups_interests" ON "groups"."id" = "groups_interests"."group_id" WHERE "groups_interests"."interest_id" = 1
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: groups_interests.interest_id: SELECT "groups".* FROM "groups" INNER JOIN "groups_interests" ON "groups"."id" = "groups_interests"."group_id" WHERE "groups_interests"."interest_id" = 1
I think I have a misunderstanding about foreign keys and the has_many relation
To get the error I used rails c
Interest.find(1).groups
I also want this command to run correcty
Groups.find(5).interests
class Group < ActiveRecord::Base
attr_accessible :description, :name, :project_id
has_many :students
has_many :group_interests
has_many :interests, :through => :group_interests
belongs_to :project
validates :name, presence: true, uniqueness: { case_sensitive: false }
end
class Interest < ActiveRecord::Base
attr_accessible :name
has_many :group_interests
has_many :groups, :through => :group_interests
validates :name, presence: true, uniqueness: { case_sensitive: false }
end
class GroupInterest < ActiveRecord::Base
attr_accessible :group_id, :interest_id
belongs_to :groups
belongs_to :interests
end
I got the idea to do this from ruby on rails guides
The reason for your error: there are two typos
class GroupInterest < ActiveRecord::Base
attr_accessible :group_id, :interest_id
belongs_to :groups #should be :group
belongs_to :interests #should be :interest
end
Group has_many :group_interests (plural)
GroupInterest belongs_to :group (singular)
EDIT - Do not use has_and_belongs_to_many unless you are sure that you will never need a new attribute in the association table. has_many :through is much more flexible.
Why don't you use has_and_belongs_to_many:
class Group < ActiveRecord::Base
attr_accessible :description, :name, :project_id
has_many :students
has_and_belongs_to_many :interests
belongs_to :project
validates :name, presence: true, uniqueness: { case_sensitive: false }
end
class Interest < ActiveRecord::Base
attr_accessible :name
has_and_belongs_to_many :groups
validates :name, presence: true, uniqueness: { case_sensitive: false }
end
class GroupInterest < ActiveRecord::Base
attr_accessible :group_id, :interest_id
end
You need to change your table structure on join_table. See the link provided for that.
class GroupInterest < ActiveRecord::Base
attr_accessible :group_id, :interest_id
belongs_to :group
belongs_to :interest
end
Group.find(5).interests

Multiple associations

I have an event, a vendor, and a venue model.
An event can have multiple vendors but one venue.
A venue can have multiple vendors and multiple events.
A vendor can have multiple venues and multiple events.
I have an events table, a venues table, a vendor table, an events_vendor table and a events_venue table.
How do I have to setup my models?
class Event < ActiveRecord::Base
attr_accessible :name, :budget, :client, :date, :description, :attendees,
:assets_attributes, :tag_list
belongs_to :user
has_many :assets, :dependent => :destroy
has_many :vendors
has_one :venue
accepts_nested_attributes_for :assets, :allow_destroy => true
acts_as_taggable
end
class EventsVendors < ActiveRecord::Base
attr_accessible :event_id, :vendor_id
end
class EventsVenues < ActiveRecord::Base
attr_accessible :event_id, :venue_id
end
class Vendor < ActiveRecord::Base
attr_accessible :city, :contact, :country, :description, :email, :employees,
:latitude, :longitude, :minimum, :name, :state, :street, :tel, :type
belongs_to :event
end
class Venue < ActiveRecord::Base
attr_accessible :capacity, :city, :contact, :country, :email, :exclusiveVendors, :fee,
:latitude, :longitude, :name, :state, :street, :tel, :union
belongs_to :event
has_many :vendors
end
Does my events_venues model belong to both events and venues? Do I have to specify the :through relationship?
Any help would be appreciated. thanks!
Yes, the join tables should look something like this.
EventsVenues
belongs_to :event
belongs_to :venue
Event
has_many :venues, through: :events_venues
has_many :events_venues
Venues
has_many :events, through: :events_venues
has_many :events_venues

Rails 3 - WARNING: Can't mass-assign protected attributes: user_ids

I have a has_many through relationship between Course and User.
class Course < ActiveRecord::Base
belongs_to :user
has_many :enrollments, :dependent => :delete_all
has_many :users, :through => :enrollments
attr_accessible :description, :duration, :name, :prerequisites, :short_name, :start_date, :user_id
accepts_nested_attributes_for :users, :allow_destroy => true
attr_accessible :users_attributes
and User:
class User < ActiveRecord::Base
has_many :subjects, :class_name => "Course" # to get this call user.subjects
has_many :enrollments, :dependent => :delete_all
has_many :courses, :through => :enrollments
and Enrollment:
class Enrollment < ActiveRecord::Base
belongs_to :course
belongs_to :user
attr_accessible :course_id, :user_id
end
Now I'm trying to set user_ids from inside Course, using a nested form. It keeps giving me that Mass Assignment warning, and nothing is saved. I read I was supposed to add attr_accessible user_id but it still doesn't work.
Even if I do something like this from the rails console:
#c.update_attributes({:user_ids => [7,8]})
with #c being the course
Any help would be greatly appreciated,
Thank you.
It's user_ids, not user_id.
You need to add user_ids to your attr_accessible.

has_many :through + polymorphic relationships

I using rails3 and trying to build some complex associations.
I have Product, Version and Property models.
class Version < ActiveRecord::Base
belongs_to :product
has_many :specs
has_many :properties, :through => :specs
end
class Product < ActiveRecord::Base
has_many :versions
has_many :specs
has_many :properties, :through => :specs
end
class Property < ActiveRecord::Base
end
class Spec < ActiveRecord::Base
belongs_to :product
belongs_to :spec
belongs_to :version
end
It works perfect, but i want to use product and version as polymorphic relations, so table specs will have only spec_id and some_other_id, instead of spec_id, product_id, version_id.
I can't figure out where i should put :as and where :polymorphic => true. Can you help me?
How about:
class Version < ActiveRecord::Base
belongs_to :product
has_many :specs, :as => :speccable
has_many :properties, :through => :specs
end
class Product < ActiveRecord::Base
has_many :versions
has_many :specs, :as => :speccable
has_many :properties, :through => :specs
end
class Property < ActiveRecord::Base
end
class Spec < ActiveRecord::Base
belongs_to :speccable, :polymorphic => true
belongs_to :spec
end
#table: specs(id,spec_id,speccable_type,speccable_id)