has_and_belongs_to_many and has_many_through on same model - ruby-on-rails

Is it acceptable to have a has_and_belongs_to_many: association as well as a has_many through: relationship on models? For instance, I have three models, Facility, Athlete, and Event.
An Athlete has and belongs to many Facilities, and vice versa. I need to allow for Facilities to create Events that belong to both the facility and the athlete. So I have the following.
class Athlete < ActiveRecord::Base
attr_accessible :age, :email, :facility_id, :name
has_and_belongs_to_many :facilities
has_many :events
has_many :facilities, :through => :events
end
class Facility < ActiveRecord::Base
attr_accessible :name, :contact_email, :contact_name, :telephone
has_and_belongs_to_many :athletes
has_many :events
has_many :athletes, :through => :events
end
class Event < ActiveRecord::Base
attr_accessible :athlete_id, :facility_id, :rfd250, :rfd50, :rfd85
belongs_to :athlete
belongs_to :facility
end
My hope with this setup is that from Facilities#Show, I can create new Athletes associated with a particular Facility (athletes_facilities table). After which I can display only those athletes associated with the Facility, and create new Events for them.
Is this the wrong way to approach the problem?

Related

Getting Association through self-inheriting STI model

In my Rails app I have Users and Forms.
class User < ActiveRecord::Base
has_many :admin_roles
#desired association below
#has_many :forms, through: :admin_roles
end
class Form < ActiveRecord::Base
has_one :department
end
The Users need to administrate the Forms through any level of an Organization.
class AdminRole < ActiveRecord::Base
belongs_to :organization
belongs_to :user
end
If assigned to a non-department organization the forms they have control over should come through the child departments.
The Forms are assigned to a departmental level only.
My model for the Organization is an STI model of 3 levels: market>subdomain>department
class Organization < ActiveRecord::Base
self.inheritance_column = :org_level
has_many :admin_roles
end
class Department < Organization
belongs_to :sub_domain, primary_key: :id, foreign_key: :parent_id
has_many :forms
end
class SubDomain < Organization
belongs_to :market, primary_key: :id, foreign_key: :parent_id
has_many :departments
end
class Market < Organization
has_many :sub_domains
end
The desired capability is to do user.forms and get all the associated forms back.
For example: Given there was a hierarchy of FooMarket>BarDomain>LoremDepartment
and a Form associated to LoremDepartment.
If a User is then tied to any of those 3 Organizations through the AdminRole it would allow for the return of the LoremDepartment Form.
Do you have to necessarily do it with associations ? u can always define an instance method in user model and back track it to forms.
But before that, just a reminder, you have to mention the foreign key in both the models for the association to work both ways.
class User < ActiveRecord::Base
attr_accessible :name
has_many :admin_roles
has_many :organizations, :through => :admin_roles
def forms
organizations.map(&:forms).flatten.uniq
end
end
class Department < Organization
belongs_to :sub_domain, primary_key: :id, foreign_key: :parent_id
has_many :forms, :foreign_key => :organization_id
end
class SubDomain < Organization
belongs_to :market, primary_key: :id, foreign_key: :parent_id
has_many :departments, foreign_key: :parent_id
def forms
departments.map(&:forms).flatten
end
end
class Market < Organization
has_many :sub_domains, foreign_key: :parent_id
def forms
sub_domains.map(&:forms).flatten
end
end
I tested this and it does work. But kinda round about.

find_or_create on a has many through relationship

I have a has many through relationship in my app:
Shows has many Bands through => Lineups
Bands are unique by :name
class Show < ActiveRecord::Base
attr_accessible :city_id, :title, :dateonly, :timeonly, :image, :canceled, :venue_attributes, :bands_attributes
belongs_to :city
belongs_to :venue
has_many :lineups
has_many :bands, through: :lineups
has_and_belongs_to_many :users
end
class Lineup < ActiveRecord::Base
belongs_to :show
belongs_to :band
end
class Band < ActiveRecord::Base
attr_accessible :name, :website, :country, :state
has_many :lineups
has_many :shows, through: :lineups
validates :name, presence: true
validates_uniqueness_of :name
before_save :titleize_name
private
def titleize_name
self.name = self.name.titleize
end
end
New Bands are created like this:
(lets say we have a show record already saved called s1)
> s1.bands.new(name: "Wet Food")
> s1.save
Right now this will only save if a band named "Wet Food" doesn't already exist
In which model is the best place to do a Band.find_or_create in this relationship so that an existing band can be used if one with the same name exists?
This is generally the type of call that would go in a Controller (or maybe a service object), but not in a Model. It really depends on the particular user flow that you're trying to accomplish in your app. Basically, where ever you are already using s1.bands.new, you could use this instead :
s1.bands.where(name: 'Wet Food').first_or_create

Rails 3 / Active Record - Association problems with additional model in assignment table

I currently have a setup that links the models User, Dealer and Role together. User and Dealer is many to many, and is working as expected with a Dealer_user assignment table.
The problem is that I want to have roles assigned to the user that are specific to the dealer also (i.e. a user could be a Sales Manager and a Parts Manager in one dealership, while being a Sales Manager and a Director in another).
In order to do this, I have a Role model (which belongs to a Role_type). Role should belong to Dealer_user, and Dealer_user has many Roles.
The intention is that I will be able to do dealer.users.where(:id => user.id).first.roles and it will return only the roles specific to that dealership.
The problem I have is that when I run the following test code: dealer.users.where(:id => user.id).first.roles.create(:role_type_id => 1 + Random.rand(4))
I get an error: Cannot modify association 'User#roles' because the source reflection class 'Role' is associated to 'DealerUser' via :has_many.
Can anyone suggest what I am doing wrong with my models (which are below)?
NOTE: The belongs_to relationship that Role has with Dealer_user is polymorphic because it could also belong to Sale_user or other association tables, which require the same functionality as Dealer.
class Dealer < ActiveRecord::Base
attr_accessible :name, :address_id
has_many :dealer_users
has_many :users, :through => :dealer_users
has_many :roles, :through => :dealer_users
end
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name
has_many :dealer_users
has_many :dealers, :through => :dealer_users
has_many :roles, :through => :dealer_users
end
class DealerUser < ActiveRecord::Base
attr_accessible :dealer_id, :user_id
belongs_to :dealer
belongs_to :user
has_many :roles, :as => :role_originator
end
class Role < ActiveRecord::Base
attr_accessible :role_type_id
belongs_to :role_type
belongs_to :role_originator, :polymorphic => true
end
Edit: No luck so far - can anyone help?
I would use has_many through association with the roles table. Get rid of the dealer_user table, and add columns to the roles table dealer_id and user_id
Then your models would look something like this:
class Dealer < ActiveRecord::Base
has_many :users, :through => :roles
has_many :roles
end
class User < ActiveRecord::Base
has_many :dealers, :through => :roles
has_many :roles
end
class Role < ActiveRecord::Base
belongs_to :dealer
belongs_to :user
end
That should make it easier to do the types of queries you're trying. The rails guide has a really good overview here

How would I route this hierarchy

I am creating an app that tracks a users employments and where they are in the companies. I need some help trying to route the app, I has made scaffolds of user, company, and department.
user
company (user has_many :through => employments)
department
user.rb
class User < ActiveRecord::Base
#associations
has_many :employments
has_many :companies, :through => :employments
has_one :department, :through => :employments
end
employment.rb
class Employment < ActiveRecord::Base
belongs_to :user
belongs_to :company
belongs_to :department
has_many :employment_histories
end
employment_history.rb
class EmploymentHistory < ActiveRecord::Base
belongs_to :employment
end
company.rb
class Company < ActiveRecord::Base
has_many :employments
has_many :users, :through => :employments
has_many :departments
end
department.rb
class Department < ActiveRecord::Base
belongs_to :company
end
For routing, the simplest way to do it is to declare your resources as resources, and then you access them through the id of the object.
http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default
Then to find through associations, I suggest you check out this railscast: http://railscasts.com/episodes/3-find-through-association?view=asciicast
If routing and finding through associations doesn't come easily, you will probably want to refactor your hierarchy to make more sense metaphorically. For instance my approach would be:
User has_many :employments and give it default_scope order: 'employments.created_at DESC' in the User model to make sure the most recent employment is first.
Employment has_one :department
Department belongs_to :company
Company has_many :departments
Then you can access all of this data through associations (see link above). You only need to route the resources, and then know how to access them in the right controllers.

Proper Rails association setup

Im setting up a reminder service that sends deals via email in relation to a persons interests AND city.. Basically, the user inputs important dates (friends bday, anniversary ect) and the interests of that special person.
I want to send them deals based on 1)the users city and 2)the interests of the related person
How should i setup my associations for the Deal model?
What i have so far..
class User < ActiveRecord::Base
belongs_to :city
has_many :person_interests, :as => :person
has_many :interests, :through => :person_interests
end
class City < ActiveRecord::Base
attr_accessible :name
belongs_to :province
has_many :users
end
class PersonInterest < ActiveRecord::Base
belongs_to :interest
belongs_to :person, :polymorphic => true
end
class Interest < ActiveRecord::Base
has_many :person_interests
end
Thanks!
If a deal could apply to more than one interest, you'd start with something like:
class Deal < ActiveRecord::Base
belongs_to :interests
belongs_to :city
end
class City < ActiveRecord::Base
attr_accessible :name
belongs_to :province
has_many :users
has_many :deals
end
class Interest < ActiveRecord::Base
has_many :person_interests
has_many :deals
end
And then you could do something like
#relevant_deals = #city.deals.where(:interest_id => 'abc')
or
#relevant_deals = #interest.deals.where(:city_id => 'def')

Resources