Instantiating a model with association - ruby-on-rails

I have a question regarding instantiating a model with a belongs_to association.
Taken from the start of http://guides.rubyonrails.org/association_basics.html :
class Customer < ActiveRecord::Base
has_many :orders, :dependent => :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
This instantiation works:
#order = #customer.orders.create(:order_date => Time.now)
But would this work just as well?
class Order < ActiveRecord::Base
attr_accessible :customer
belongs_to :customer
end
#customer = Customer.new
#order = Order.create(:customer => #customer)
My experiments indicate that it does, to some extent.. But since associations are loaded lazily, it might be tricky in some cases (I can give one example, if you'd like).
So my question is:
To what extent does that instantiation work just as well as the former?

These two forms both work.
Either way you have an Order object with a customer_id field set to the ID of an existing customer. When you call customer.orders.create() it's populating that association behind the scenes. In your second example you are doing it manually.

Related

Question about controllers, dependent models, and controller functions

I'm new to ruby on rails and I'm thoroughly confused from all the documentation online. I'm creating a database program that keeps track of orders. I've already setup the has_one, belongs_to, and has_many associations in the model and I can verify their relationship with my sqlbrowswer.
Here's an rough illustration of the models.
Models
Each order has only one product, one service, one bill, and each bill can have many charges. The same product may appear in different orders, but each order would be unique.
I also have an order_observer model to create dependent models of the product
class OrderObserver < ActiveRecord::Observer
observe :order
def after_create(order)
Product.create! :order_id => order.id
Service.create! :order_id => order.id
Bill.create! :order_id => order.id
end
end
Here's what my product class and order class look like:
class Product < ApplicationRecord
belongs_to :order
end
class Order < ApplicationRecord
has_one :product, dependent: :destroy
has_one :bill, dependent: :destroy
has_one :service, dependent: :destroy
accepts_nested_attributes_for :product
accepts_nested_attributes_for :bill
accepts_nested_attributes_for :service
end
Now, what I'm confused on is how to update the dependent models. Should I implement multiple controllers for each model or just one controller to handle the whole thing?
Right now all I have in my main controller is:
def create
#order = Order.new(order_params)
end
def edit
#order = Order.find(params[:id])
end
def update
end
I would appreciate any tips or guidance.
Thanks!
Now, what I'm confused on is how to update the dependent models. Should I implement multiple controllers for each model or just one controller to handle the whole thing?
You can do this whatever you want, but you should always remember the idea 'resources', In this case, each model represents a resource, so you should do it separately.
The Rails program is based on resources, as you can see that in 'routes.rb'.

Rails: Multiple relationships between two models

I'm creating a Database Migration in Rails 4.0.4, and I want to capture the following relationship:
A customer has many credit cards. A customer has only one default credit card.
and here's what I think it should look like.
class Customer < ActiveRecord::Base
has_many :cards
has_one :card # i.e. has one default card
end
class Card < ActiveRecord::Base
belongs_to :customer
end
Is this correct? If so, how does Rails know which relationship the belongs_to in the Card class refers to? If it's incorrect (and I'm guessing it is), please help me fix it.
I'd put the scope on the card's side, seems easier for me
class Customer < ActiveRecord::Base
has_many :card
end
class Card < ActiveRecord::Base
belongs_to :customer
scope :default, -> { where is_default: true }
end
default_card = customer.cards.default
Currently your code is enough to confuse Rails by having has_one :card and has_many :cards.You should be using class_name option provided specially for these type of associations.
Something like this should work for you
class Customer < ActiveRecord::Base
has_many :cards
has_one :default_card, :class_name => "Card"
end
foreign_key
To add to Pavan's answer, you'll need to use some sort of condition to determine which is the default card.
Because Rails' relational database structure relies on foreign_keys to pull the related data, you'll need to either assign the correct foreign_key for your default_card, or use a condition to find it:
#app/models/customer.rb
Class Customer < ActiveRecord::Base
has_one :default_card, -> { where default: true" },class: "Card", foreign_key: "customer_id"
end
This would rely on having the boolean column default in your cards table

How do I handle using 1 model to belong_to 2 different models at different times?

I am creating a Shopping Cart.
So I will have a model called LineItem.
Each instance of a cart will have 1+ line items. As will a completed transaction - which becomes an 'order'.
So, in theory, a LineItem belongs_to Cart and also belongs_to Order.
But, what would the DB table look like? a cart_id and order_id in my LineItems table?
That would mean that for every valid cart record, there will be an order_id that is nil (or empty). Likewise, for every valid order, there will be an empty cart_id.
This seems like a non-Railsy way to do this.
What is the best way to do this? A polymorphic association? What would that look like if I should do that?
The line item model can have two belongs_to associations
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :order
end
But this can get messy if it needs to belong to several different classes. The solution is polymorphic association which allows a model to belong to more than one model on a SINGLE association, which in the example below is :line_itemable. It will add two attributes, line_itemable_id and line_itemable_type to the LineItem model.
class LineItem < ActiveRecord::Base
belongs_to :line_itemable, :polymorphic => true
end
class Order < ActiveRecord::Base
has_many :line_items, :as => :line_itemable
end
class Cart < ActiveRecord::Base
has_many :line_items, :as => :line_itemable
end
If cart and order share similar attributes such as cost, then another option is to eliminate the order class and simply add a :paid flag on the cart.
I would suggest polymorphic association.
class LineItem < ActiveRecord::Base
belongs_to :owner, :polymorphic => true
end
class Order < ActiveRecord::Base
has_many :line_items, :as => :owner
end
class Cart < ActiveRecord::Base
has_many :line_items, :as => :owner
end
you will need to add owner_type and owner_id to line_items table.
Refer this

Rails Associations for Lookup Table

I have a Statuses table which contains only an id and name field (Active, Inactive, Pending, etc). I then have tables such as Users, Achievements, Badges for which each of these contain a status_id foreign key. Do the associations in my models look correct?
class Status < ActiveRecord::Base
has_many :achievements
has_many :badges
has_many :users
end
class User < ActiveRecord::Base
belongs_to :status
end
class Badge < ActiveRecord::Base
belongs_to :status
end
class Achievement < ActiveRecord::Base
belongs_to :status
end
I am struggling with how to properly read the difference between has_one and has_many in the case of a lookup table. I know that a user has one company and has one profile and a company has many users but this seems backwards to me.
The simplest association setup would be:
class User < ActiveRecord::Base
has_one :status
end
That exactly describes what you have posted. Your solution would work, but it is overkill for what you've described. All the association I posted above would do is add one method to the user model, i.e.
#user = User.find(1)
#user.status
If on the other hand you wanted simple semantics for showing all the users with a particular status, THEN you'd add
class Status < ActiveRecord::Base
has_many :users
end
so now you could do:
#status = Status.find_by_description('Active').first()
#status.users
Note that in BOTH cases, all that is needed is for the users model to have an attribute 'status_id'
Belongs_to is better suited when there is an implicit hierarchy , i,e,
class Child << ActiveRecord::Base
belongs_to :parent
end

Create and destroy HABTM associations - not actual records?

This is similar to a previous question, but our approach has changed a little since.
I need to be able to destroy the associations between Releases & Tracks + Products & Tracks without destroying the track itself. I need to then be able to re-associate a Track with any Release or Product.
My models are as follows:
class Release < ActiveRecord::Base
has_many :products, :dependent => :destroy
has_and_belongs_to_many :tracks
end
class Product < ActiveRecord::Base
belongs_to :release
has_many :releases_tracks, :through => :release, :source => :tracks
has_and_belongs_to_many :tracks
before_save do
self.track_ids = self.releases_track_ids
end
end
class Track < ActiveRecord::Base
has_and_belongs_to_many :releases
has_and_belongs_to_many :products
end
class ReleaseTracks < ActiveRecord::Base
belongs_to :release
belongs_to :track
end
class ProductsTracks < ActiveRecord::Base
belongs_to :product
belongs_to :track
end
Can anyone help with the appropriate controller methods please?
If I use the following on a Product Track for example, it destroys the track and association:
#product = Product.find(params[:product_id])
#track = #product.tracks.find(params[:id])
#track.destroy
I've tried something like this but it gives me a notmethoderror:
#product = Product.find(params[:product_id])
#track = #product.products_tracks.find(params[:track_id])
#track.destroy
Can anyone point me in the right direction? As I say, I need this primarily on destroy, but i also need to then be able to re-create associations.
has_and_belongs_to_many (HABTM) is one way of declaring a many-to-many relationship between two models. Under the covers, rails uses a simple join table (a table with two columns only, each a foreign key to the primary key of the main tables). The association exists when a record in the join table exists. I am not sure how destroy works by default in this case, but it may decide to delete all of the associated records (not just the association). You may be able to control this by using the dependent <action> clause on the HABTM declaration. The relationship is created when you assign one or more "children" to a parent and save.
In this case, maybe what you want is a pair of has_many :through relations -- the "through" is a relation, but can be treated as a first class model, and extended and operated on with ActiveRecord, meaning you can get at a specific release track (for example) and decide to delete it without affecting either association.
There's a good section on when to use one vs. the other in this Rails Guide: http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many

Resources