rails model assignment with has_many :through - ruby-on-rails

I just can't figure out how to create a relation with a join table. I've read all the posts about them, but the main error seems to be that in the join table to models should be singular, which I have. I just can seem to create the models correctly and assign them. I have projects with datasets, and projects can have multiple datasets, while a dataset can belong to multiple projects. A dataset can be active or not, which is why I need the has_many through instead of the has_many_and_belongs_to setup.
My model definitions are:
class Project < ActiveRecord::Base
attr_accessible :name, :user_id
belongs_to :user
has_many :activedatasets
has_many :datasets, :through => :activedatasets
end
class DataSet < ActiveRecord::Base
attr_accessible :name, :project_id, :filename, :tempfilename
has_many :activedatasets
has_many :projects, :through => :activedatasets
end
class ActiveDataSet < ActiveRecord::Base
attr_accessible :active, :data_set_id, :project_id
belongs_to :project
belongs_to :dataset
end
When I create a new dataset I've got the project_id in the params, so I'm trying to setup the relationship like below:
class DataSetsController < ApplicationController
def new
#dataset = DataSet.new
#dataset.activedatasets.project_id = params[:project_id]
end
end
The error I'm getting seems famous:
NameError in DataSetsController#new
uninitialized constant DataSet::Activedataset
Can anybody point me in the right direction please?
Thanks for you attention.

You need to use:
has_many :active_data_sets
has_many :data_sets, :through => :active_data_sets
And in the DataSet model:
has_many :active_data_sets
has_many :projects, :through => :active_data_sets
Basically, rails expects you to use underscores to separate words in association names, and converts them to CamelCase. So active_data_sets becomes ActiveDataSet. Rails then uses this to work out which model class the association is with.
You also need to change your controller to this:
class DataSetsController < ApplicationController
def new
#dataset = DataSet.new
#dataset.active_data_sets.build(:project_id => params[:project_id])
end
end
Otherwise you'll get an error because you tried to set the project_id of the active_data_sets collection rather than creating a new ActiveDataSet.

Related

Understanding Polymorphic Associations in Rails

I have a parent model called Quote. which has an attribute called final_quote and has a child model called QuoteBoms, which has attributes called quote_final_quote and quantity and total_quote (=quote_final_quote * quantity)
class Quote < ActiveRecord::Base
has_many :quote_boms, dependent: :destroy
accepts_nested_attributes_for :quote_boms, :reject_if => :all_blank, :allow_destroy => true
class QuoteBom < ActiveRecord::Base
belongs_to :quote
has_many :quotes
end
Now in the nested model, I am selecting the quote with the association "belongs_to :quote" but has_many :quotes does not work as I have only one quote_id column (I suppose this is the problem). I see that i need to define a third class as quotebom_quote_id but cannot figure out how exactly!
Any help will be greatly appreciated!
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Profile < ActiveRecord::Base
has_many :images, :as => :imageable
end
class Article < ActiveRecord::Base
has_many :images, :as => :imageable
end
This is how we have made a single Image model and it is accessed by one or more than one model
Please refer this
Link
From what I can tell, you wish to create a database structure containing the models Quote and QuoteBom where a Quote has many QuoteBom and QuoteBom belongs to many Quotes.
That being the case, you will want to use a has_and_belongs_to_many association.
This will require adding to your models
class Quote < ActiveRecord::Base
has_and_belongs_to_many :quote_boms
end
class QuoteBom < ActiveRecord::Base
has_and_belongs_to_many :quotes
end
...and the following migration (assuming Quote and QuoteBom already exist)
class CreateQuotesAndQuoteBoms < ActiveRecord::Migration
def change
create_table :quote_quote_boms, id: false do |t|
t.belongs_to :quote, index: true
t.belongs_to :quote_bom, index: true
end
end
end
By having the associations above in the model and this table in your database, rails will automagically handle the associations between quote and quote_doms. As a result, you will also be able to access quote_dom.quotes which you said you weren't able to do in your question.
This is NOT a polymorphic association. A polymorphic association allows a model to belong to more than one type of other model in a single association.

Is there a better way to get many to many associations records' propertity list in ActiveRecord

I have created two models(User, Project) with many to many associations and create a association table(ProjectUser):
class User < ActiveRecord::Base
attr_accessor :name, :email
has_many :project_users
has_many :projects, through: :project_users
end
class Project < ActiveRecord::Base
attr_accessor :name, :address
has_many :project_users
has_many :users, through: :project_users
end
class ProjectUser < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
With association specified, I can get a user's projects like this:
projects = User.find('user_id').projects
While if I just want project name list, is there any method works like this:
# This will get NoMethod error
project_names = User.find('user_id').projects.names
Now I do it like this:
project_names = User.find('user_id').projects.map {|project| project.name}
I'm wondering is there any syntactic sugar to do like this :)
If all you want is the names you should be able to do a join on the project_users table and simply pluck the names:
project_names = Project.joins(:project_users).where(user_id: 'user_id').pluck(:name)
If you already have the user then I'd just do it through the association like you have.
#user = User.find(params[:id])
project_names = #user.projects.pluck(:name)
More info on pluck here

ActiveRecord won't build the right class using STI

I'm using single table inheritance in my application and running into problems building inherited users from an ancestor. For instance, with the following setup:
class School < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
attr_accessible :type #etc...
belongs_to :school
end
Class Instructor < User
attr_accessible :terms_of_service
validates :terms_of_service, :acceptance => true
end
Class Student < User
end
How can I build either a instructor or student record from an instance of School? Attempting something like School.first.instructors.build(....) gives me a new User instance only and I won't have access to instructor specific fields such as terms_of_service causing errors later down the rode when generating instructor-specific forms, building from console will give me an mass-assignment error (as it's trying to create a User record rather than an Instructor record as specified). I gave the example of School, but there are a few other associations that I would like to inherit from the User table so I don't have to repeat code or fields in the database. Am I having this problem because associations can not be shared in an STI setup?
You should specify instructors explicitly
class School < ActiveRecord::Base
has_many :users
has_many :instructors,:class_name => 'Instructor', :foreign_key => 'user_id'
end
And what else:
class School < ActiveRecord::Base
has_many :users
has_many :instructors
end
class Instructor < User
attr_accessible :terms_of_service # let it be at the first place. :)
validates :terms_of_service, :acceptance => true
end
OK it seems part of the problem stemmed from having the old users association inside of my School model. Removing that and adding the associations for students and instructors individually worked.
Updated School.rb:
class School < ActiveRecord::Base
#removed:
#has_many :users this line was causing problems
#added
has_many :instructors
has_many :students
end

Adding many models to another model

I'm currently working on a small project using Ruby On Rails 3.2 to create a database that contains several unique Models. Each Model has many Elements and each Element has the potential to belong to many Models. I have been able to set up the models in the following manner:
class Model < ActiveRecord::Base
has_many :model_elements
has_many :elements, :through => :model_elements
attr_accessible :elements, :name, :notes, :ref
end
class Element < ActiveRecord::Base
has_many :model_elements
has_many :models, :through => :model_elements
attr_accessible :elementType, :name, :notes, :ref
validates_presence_of :name
end
class ModelElement < ActiveRecord::Base
belongs_to :Model
belongs_to :element
attr_accessible :model_id, :created_at, :element_id
end
My question is how do I add multiple Elements to a single Model? I've tried to find some documentation but I can't find anything. Currently I'm trying to do the following:
#model.elements = #element
Where #element is a predefined element however it's throwing the following error:
undefined method `each' for #<Element:0x007ff803066500>
Any help would be greatly appreciated.
Try
#model.elements << #element
collection.create(attributes = {})
Returns a new object of the collection type that has been instantiated with attributes, linked to this object through the join table, and that has already been saved.
#model.elements.create(:name => "example")
Amar's answer is correct. If you wanted you can simplify your models further by using the has_and_belongs_to_many association.
class Model < ActiveRecord::Base
has_and_belongs_to_many :elements, :join_table => :model_elements
end
class Element < ActiveRecord::Base
has_and_belongs_to_many :models, :join_table => :model_elements
end
#model.elements << #element

Rails - Query with has_many association

I am currently trying to create a custom method on a model, where the conditions used are those of a has_many association. The method I have so far is:
class Dealer < ActiveRecord::Base
has_many :purchases
def inventory
inventory = Vehicle.where(:purchases => self.purchases)
return inventory
end
end
This is not working, due to the fact that Vehicle has_many :purchases (thus there is no column "purchases" on the vehicle model). How can I use the vehicle.purchases array as a condition in this kind of query?
To complicate matters, the has_many is also polymorphic, so I can not simply use a .join(:purchases) element on the query, as there is no VehiclePurchase model.
EDIT: For clarity, the relevant parts of my purchase model and vehicle models are below:
class Purchase < ActiveRecord::Base
attr_accessible :dealer_id, :purchase_type_id
belongs_to :purchase_item_type, :polymorphic => true
end
class Vehicle < ActiveRecord::Base
has_many :purchases, :as => :purchase_item_type
end
class Dealer < ActiveRecord::Base
def inventory
Vehicle.where(:id => purchases.where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type_id))
end
end
Or:
def inventory
purchases.includes(:purchase_item_type).where(:purchase_item_type_type => "Vehicle").map(&:purchase_item_type)
end
I was able to do this using the :source and :source_type options on the Vehicle model, which allows polymorphic parents to be associated.

Resources