Multiple associations - ruby-on-rails-3

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

Related

ActiveRecord::HasManyThroughNestedAssociationsAreReadonly Error in Rails Admin

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

How to insert multiple rows based on a defaults table?

I have the following tables: Users, Default Prices, Clients, Client Prices. What I'd like is to have the default_prices automatically fill in the client_prices table when a new client is created. It looks like I might be able to use a similar solution to this answer. What I would like to happen is when a new client is created by a user, all of the client_prices for the client are populated by the default_prices table.
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :stripe_token, :default_prices_attributes
has_many :default_prices
has_many :clients
accepts_nested_attributes_for :default_prices, :allow_destroy => true
class DefaultPrice < ActiveRecord::Base
attr_accessible :price, :user_id, :visit_type, :id
belongs_to :user
end
class Client < ActiveRecord::Base
attr_accessible :active, :address_1, :address_2, :city, :email, :first_name, :last_name, :state, :user_id, :zip, :client_prices_attributes
belongs_to :user
has_many :client_prices
accepts_nested_attributes_for :client_prices_attributes
class ClientPrice < ActiveRecord::Base
attr_accessible :price, :client_id, :visit_type, :id
belongs_to :uclient
end
You can add before_create block to copy default price.
before_create do
user.default_prices.each do |default_price|
client_prices.build(default_price.attributes.slice("price", "visit_type"))
end
end

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.

Rails ActiveRecord Query (Cross model)

I have an app that lets users input dates & interests that relate to those dates .I need to send them deals (a few days before the date - Via Email) that are based off of their interests and location. I have all the models setup and recording the data properly, just wondering how to query the models for the dates and then send the appropriate deal based off of the city and interests.
Notes:
*Each city and interest category has only 1 deal
*I have several different models for types of dates (Holidays, Occasions, Friends Birthdays ect).. all are pretty much identical in structure.
*All interests for each type of date are stored in person_interests.
Models:
Class User
belongs_to :province
belongs_to :city
has_many :friends_bdays
has_many :occasions
has_many :person_interests, :as => :person
has_many :interests, :through => :person_interests
has_many :user_holidays
has_many :holidays, :through => :user_holidays
has_many :anniversaries
end
class Deal < ActiveRecord::Base
belongs_to :interest
belongs_to :city
belongs_to :store
end
class Store < ActiveRecord::Base
has_many :deals
belongs_to :city
belongs_to :province
end
class PersonInterest < ActiveRecord::Base
belongs_to :interest
belongs_to :person, :polymorphic => true
end
class Interest < ActiveRecord::Base
has_many :person_interests
has_many :deals
end
class Occasion < ActiveRecord::Base
belongs_to :user
belongs_to :admin_user
has_many :person_interests, :as => :person
has_many :interests, :through => :person_interests
end
class Anniversary < ActiveRecord::Base
belongs_to :user
has_many :person_interests, :as => :person
has_many :interests, :through => :person_interests
end
class Friend_bday < ActiveRecord::Base
belongs_to :user
has_many :person_interests, :as => :person
has_many :interests, :through => :person_interests
end
You can achieve this using a variation of the solution below:
Install the squeel gem
class User
def deals(reload=false)
#deals = nil if
#deals ||= Deal.where{
( (:city => city_id) | ( :interest_id => interest_ids) ) &
:deal_date => (Time.now..3.days.from_now)
}
end
end
Now, user.deals returns the deals that will be active in next 3 days matching the user's city OR interests.
Edit 1:
Based on your comment it looks like you don't need the squeel gem. You can achieve what you want using regular AR syntax.
class User
def deals(reload=false)
#deals = nil if reload
#deals ||= Deal.where(
:city => city_id,
:interest_id => interest_ids,
:deal_date => (Time.now..3.days.from_now)
)
end
end

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)