I have a parent model, a child model and a join model. How does the controller of the join model look like if I need to reference the parent_id and the child_id?
For example, I have:
def new
#join = JoinModel.new
new
def create
#join = JoinModel.new(params[:join_model])
#parent_id = current_user.id
end
My question is, how do I reference the child model object?
If I use #child = Child.find(params[:id]), it gives me the errorcan't find child without an ID`.
Help.
Thanks.
Two Tips:
1) try to use a Self-Referential model for this -- just one table instead of three tables - that's a more lean design.
2) use the "ancestry" Gem to model parents / children - it has very convenient methods to get to the parent, ancestors, or descendants.
See:
http://railscasts.com/episodes/262-trees-with-ancestry (hands-on RailsCast)
Self-referencing models in Rails 3
If you need those models to be separate, you can do something like this:
class User < ActiveRecord::Base
has_many :publications, :through => :ownership
end
class Publication < ActiveRecord::Base
has_many :users , :through => :ownership
end
class Ownership < ActiveRecord::Base # the join table
belongs_to :user
belongs_to :publication
end
and then create new publications like this:
u = User.find_by_name("John")
u.publications.new( attributes-for-new-publication )
u.save
This is not really a Parent/Child relationship, but rather "has_many through"
Related
say I have the following STI models
class Parent < ActiveRecord::Base
has_many :childs, foreign_key: 'parent_id' # forgive the english for sake of simplicity
#def childs
# Child.where(parent_id: id) # this works just fine BTW
#end
end
class BadParent < Parent
end
class GoodParent < Parent
end
and the following Child class
class Child
belongs_to :parent # parent_id lives on this
end
I dont care about setting the type on the Child so I don't care about creating a polymorphic association.
bad_parent = BadParent.create(name: 'Michael Jackson')
child = Child.create(name: 'Bobby', parent: bad_parent)
If I run
child.parent #=> <# BadParent > # AWESOME
bad_parent.childs #=> [] NO BUENO!!!
sql_statement = bad_parent.childs.to_sql #=> "SELECT `childs`.* FROM `childs` WHERE `childs`.`parent_id` = 1"
Child.find_by_sql(sql_statement) #=> [<# Child Object #>] BUENO!!!
Is there something I have to add to the association to make this work like find_by_sql?
As per other comments, you shouldn't have both a method and association named the same as it is very unclear what will get executed - I'll assume for here on you will get rid of def childs ... Aside from that I think your issue is to do with caching i.e. rails will only hit the DB if it knows something has changed. In your example bad_parent doesn't know that new children have been added. You could either reload like:
bad_parent.reload
bad_parent.childs #> should show child object now
or force a call to the DB like:
bad_parent.childs(true)
Check out 3.1 Controlling Caching section of the rials guides for more info: http://guides.rubyonrails.org/association_basics.html
Here's what I'd do...
#app/models/person.rb
class Person < ActiveRecord::Base
#columns id | type | parent_id | type_id | name | created_at | updated_at
end
#app/models/parent.rb
class Parent < Person
belongs_to :type
has_many :children, foreign_key: 'parent_id'
end
#app/models/child.rb
class Child < Parent
belongs_to :parent
end
#app/models/type.rb
class Type < ActiveRecord::Base
#columns id | type
#values good/bad (probably overkill to have DB for this)
has_many :parents
end
This should allow you to call the following:
#parent = Parent.find params[:id]
#parent.children #-> collection of Person model with parent_id attribute for parent
In regards your specific issue - about eager loading etc - I don't have masses of experience.
There are hierarchy gems which help this out.
We've used ClosureTree before - it creates a separate table which allows you to traverse hierarchies much easier. Another one is called ancestry which is pretty popular (easier to implement).
I'd recommend using the likes of ancestry in your "parent" model. I called the parent model Parent because I think it will give you much deeper scope to work with different types of data.
For example, your Child model is its own entirely, when it should be made up of the same data as the Parent.
I am having models like
// Contains the details of Parties (Users)
class Party < ActiveRecord::Base
has_many :party_races
has_many :races, :through=>:party_races
end
// Contains the party_id and race_id mappings
class PartyRace < ActiveRecord::Base
belongs_to :party
belongs_to :race
end
// Contains list of races like Asian,American,etc..
class Race < ActiveRecord::Base
has_many :party_races
has_many :parties, :through => :party_races
end
Now, lets say I'm creating an instance of Party
party_instance = Party.new
How am I supposed to add multiple Races to party_instance and save to database ?
You could use nested attributes to make one form that allows children. There are many examples on this site. Read up on the following first:
Accepts nested attributes
Fields for
A railscast about your use case
You also can create new PartyRace for each Races that you can add:
def addRace( party_instance, new_race )
party_race = PartyRace.new( party: party_instance, race: new_race )
party_race.save
end
It has been almost a week since I'm trying to find a solution to my confusion... Here it is:
I have a Program model.
I have a ProgramCategory model.
I have a ProgramSubcategory model.
Let's make it more clear:
ProgramCategory ======> Shows, Movies,
ProgramSubcategory ===> Featured Shows, Action Movies
Program ==============> Lost, Dexter, Game of Thrones etc...
I want to able to associate each of these models with eachother. I've got what I want to do particularly with many-to-many association. I have a categories_navigation JOIN model/table and all of my other tables are connected to it. By this way, I can access all fields of all of these models.
BUT...
As you know, has_many :through style associations are always plural. There is nothing such as has_one :through or belongs_to through. BUT I want to play with SINGULAR objects, NOT arrays. A Program has ONLY ONE Subcategory and ONLY ONE Category. I'm just using a join table to only make connection between those 3. For example, at the moment I can access program.program_categories[0].title but I want to access it such like program.program_category for example.
How can I have 'has_many :through's abilities but has_one's singular usage convention all together? :|
P.S: My previous question was about this situation too, but I decided to start from scratch and learn about philosophy of associations. If you want so you may check my previous post here: How to access associated model through another model in Rails?
Why a join table where you have a direct relationship? In the end, a program belongs to a subcategory, which in turn belongs to one category. So no join table needed.
class Program < ActiveRecord::Base
belongs_to :subcategory # references the "subcategory_id" in the table
# belongs_to :category, :through => :subcategory
delegate :category, :to => :subcategory
end
class Subcategory < ActiveRecord::Base
has_many :programs
belongs_to :category # references the "category_id" in the table
end
class Category < ActiveRecord::Base
has_many :subcategories
has_many :programs, :through => :subcategories
end
Another point of view is to make categories a tree, so you don't need an additional model for "level-2" categories, you can add as many levels you want. If you use a tree implementation like "closure_tree" you can also get all subcategories (at any level), all supercategories, etc
In that case you skip the Subcategory model, as it is just a category with depth=2
class Program < ActiveRecord::Base
belongs_to :category # references the "category_id" in the table
scope :in_categories, lambda do |cats|
where(:category_id => cats) # accepts one or an array of either integers or Categories
end
end
class Category < ActiveRecord::Base
acts_as_tree
has_many :programs
end
Just an example on how to use a tree to filter by category. Suppose you have a select box, and you select a category from it. You want to retrieve all the object which correspond to any subcategory thereof, not only the category.
class ProgramsController < ApplicationController
def index
#programs = Program.scoped
if params[:category].present?
category = Category.find(params[:category])
#programs = #programs.in_categories(category.descendant_ids + [category.id])
end
end
end
Tree-win!
I have a standard relationship:
class User <ActiveRecord:: Base
has_and_belongs_to_many: feeds,: uniq => true
end
class Feed <ActiveRecord:: Base
has_and_belongs_to_many: users,: uniq => true
end
And according to the rails naming convention, the join table is called
'users_feeds'.
I need to extend the functionality of join table, and add the model UserFeed (or UsersFeeds ?).
Does adding the model is a disorder of the rails convention?
Do I need to change the name of the join table, and define a relationship using the option :through?
Adding a class for your join model is fine. You should not need to change the table name. The resulting code will look something like:
class User <ActiveRecord:: Base
has_many :user_feeds
has_many :feeds, :through=>:user_feeds
end
class UserFeed <ActiveRecord:: Base
belongs_to :user
belongs_to :feed
end
class Feed <ActiveRecord:: Base
has_many :user_feeds
has_and_belongs_to_many: users, :through=>:user_feeds
end
Can a nested set have duplicate child objects or multiple parent_id/root/nodes?
For instance, I want to create an application that can manage parts and equipment. However, a specific equipment can have the same parts from other equipment as well.
Any thoughts on the best approach for this?
Thank you!!!
I think what you need here is an association class to help model the many-to-many relationship. In rails, this might look something like this:
class Equipment < ActiveRecord::Base
has_many :part_relationships
has_many :parts, :through => :part_relationships
end
class Part < ActiveRecord::Base
has_many :part_relationships
has_many :equipment, :through => :part_relationships
end
class PartRelationship < ActiveRecord::Base
belongs_to :equipment
belongs_to :part
end
There are other ways of modelling this (e.g. using a tree type structure), but if a 'set' is what you want, then this is the way I'd go.
Once this is done, you can do things like:
e = Equipment.find(:first)
e.parts # Returns all the parts on this equipment, including shared
p = Part.find(:first)
p.equipment # Returns all equipment this part features in.
# Create a new relationship between e and p
PartRelationship.create(:equipment => e, :part => p)