Understanding rails has_one has_many model associations - ruby-on-rails

I'm trying to understand a rails model association and having trouble figuring out what association I need to use:
Here's my app Models
Company ---- Subscription ---- SubscriptionType
The SubscriptionType has a list of 3 different types of subscriptions and their associated price.
A Company has_one :subscription.
A Subscription will belong_to :company.
It also has other fields, such as trial_start_date, trial_end_date, charge_date, etc.
At first, I thought that Subscription has_one SubscriptionType and SubscriptionType has_many Subscriptions however that relationship doesn't seem to work in my subscription_spec.rb
it { should have_one(:subscription_type) }
But that gives me the following error, which indicates that this relationship won't work since I don't want to have tons of records in the SubscriptionType table:
Expected Subscription to have a has_one association called subscription_type (SubscriptionType does not have a subscription_id foreign key.)
Can someone help me wrap my head around this?

The difference between has_one vs belongs_to is all about where the foreign key lives.
Subscription has_one :subscription_type means that SubscriptionType has a subscription_id column and belongs to only one Subscription.
Subscription belongs_to :subscription_type means that Subscription has a subscription_type_id column and SubscriptionType can belong to multiple Subscriptions.
So to answer your question, the correct relationship here is
class Subscription < ApplicationRecord
belongs_to :subscription_type
end
class SubscriptionType < ApplicationRecord
has_many :subscriptions
end

You can set the associations like this:
class Company < ApplicationRecord
has_one :subscription
end
# subscriptions table should have columns company_id and subscription_type_id
class Subscription < ApplicationRecord
belongs_to :company
belongs_to :subscription_type
end
class SubscriptionType < ApplicationRecord
has_many :subscriptions
end
With this setup, the associated objects can be accessed as:
company = Company.find(1)
# to get subscription object with company_id: 1
company.subscription
# to get subscription_type object of the company's associated subscription
company.subscription.subscription_type
# to get all subscriptions of a particular subscription_type
SubscriptionType.last.subscriptions
Then, your subscription_spec.rb looks like:
it { should belong_to(:company) }
it { should belong_to(:subscription_type) }

Related

Rails - db logic, scope data by company

I have 3 models: User, Receipt and Article.
Only association is: Receipt has_many Articles.
Now I need 4. model, which is Company. User belongs_to company, and Company has_many Users.
User needs to see only Receipts and Articles that are in his Company.
Do I need to have company_id in User, Receipts and Articles and browse by that id, or there is a better way?
User needs to see only Receipts and Articles that are in his Company
Tweak your associations like so
#app/models/user.rb
class User < ApplicationRecord
belongs_to :company
end
#app/models/company.rb
class Company < ApplicationRecord
has_many :users
has_many :receipts
has_many :articles, through: :receipts
end
#app/models/receipt.rb
class Receipt < ApplicationRecord
belongs_to :company
has_many :articles
end
#app/models/article.rb
class Article < ApplicationRecord
belongs_to :receipt
end
Now you can call #user.company.receipts and #user.company.articles
Do I need to have company_id in User, Receipts and Articles and browse
by that id
With the above approach, you need have company_id in users and receipts.
You definitely need to have company_id in User unless you are going with multitenancy. And you will also need to have company_id in Receipts but not in Article as it is already associated with the Receipt.
To access receipts you just need to do user.company.receipts
Create Relationship between two table
class Receipt < ApplicationRecord
belongs_to :company
end
class Company < ApplicationRecord
has_many :receipts
end
Get the Record in simple way using that the relationship in model
ex: user.company.receipt.first.article

How do i correctly implement a three way many-to-many relationship in rails 4?

I'm using rails 4 and i have a possible three way many-to-many relationship situation that looks like this: To register a sale, i need a Client and a Product, along with its quantity. The threeway comes when i need a fixed id for the Sale because of another table Installments, with due dates and values for each installment and to check if they are paid or not.
I got a little confused with the relationships between them, but i did something like this (i called the middle table i used here as SCP, sale_client_product):
class Client < ActiveRecord::Base
has_many :scps
end
class Sale < ActiveRecord::Base
has_many :scps
has_many :installments
end
class Installment < ActiveRecord::Base
belongs_to :sale
end
class Product < ActiveRecord::Base
has_many :scps
end
class SCP < ActiveRecord::Base
belongs_to :client
belongs_to :product
belongs_to :sale
end
I would like to know if this is correct or if there is a better way of doing it. I'm also in a picle when actually saving, as for any one sale i may have to save many SCP instances with one form.
If you want to have Product, Client, Sale, Installment information in a single document, maybe you can use the Invoice.
In business, if a company want to ask money from a customer, he will periodically send him an invoice which includes all the following infos:
Product details, names, quantity, price for each unit
Client details, names, address, phone number
Sale details, total price, date of sale or Installment due date, installment amount
Class Client
has_many :invoices
end
Class Product
has_many :invoices
end
Class Sale
has_many :installments
has_many :invoices, through: :installments
end
Class Installment
belongs_to :sale
end
Class Invoice
belongs_to :client
belongs_to :product
belongs_to :installment
end
Payment will be what you need to reconcile with Invoice, so that you can understand which Invoices (and consequently Installments) were paid.
Class Payment
belongs_to :invoice
end
when you do #invoice.payment you get the payment for that invoice (which belongs_to :installment), if #invoice.payment is nil, then the installment was not paid.
If you want to register a Payment it should have an existing Invoice
#payment = Payment.new(payment_params)
#payment.invoice_id = #invoice.id
#payment.save
This is kind of how I would register Accounting Transactions when I was working in the Accounting Field. Feel free to improve your app and maybe in the future we can edit this post for improvements
A possible improvement could be enstablishing that Installment has_one :payment, through: :invoice, so you figure that out!

Is it possible to store an attribute on a model, but is only accessible through the association?

I'm building an ecommerce platform and was looking over the database design.
These are the models in my ecommerce site:
class User < ApplicationRecord
belongs_to :cart, {:optional => true}
end
class Cart < ApplicationRecord
has_and_belongs_to_many :phones
has_one :user
end
class Phone < ApplicationRecord
has_and_belongs_to_many :carts # has join table with Cart
has_and_belongs_to_many :orders
end
class Order < ApplicationRecord
belongs_to :user, {:optional => true}
has_and_belongs_to_many :phones #HAS join table with Phone
end
My site is selling phones (Model Phone) to users (Model User), who put them in carts (Model Cart), and once the order gets submitted, an order gets created (Model Order).
I want to update the quantities sold by putting #user.cart.phones (#user = current user) into the Order model, after the purchase has been submitted and finalized. The trouble I'm having is how I should design the database schema in so that I can track the type of phone being sold, and how many of that particular phone were sold in the order.
I was thinking something along the lines of #user.order.phones, and have an attribute called quantity on the Phone model. The problem with that is that the Phone model would be accessible to all users, hence, it would overwritten the moment another user submitted their order.
My question is, is it possible to have an attribute on the Phone model, only accessible to #user.cart (i.e.: #user.cart.phones.phones_sold --> .phones_sold would only be available through #user.cart and would be unique for each user)? If not, how could I go about designing my Model/Database to include an order model that has information about each order (type of phone, and quantity sold) that's unique to each individual user?
you have
class Cart < ApplicationRecord
has_and_belongs_to_many :phones
end
class Phone < ApplicationRecord
has_and_belongs_to_many :carts # has join table with Cart
end
and this is a good start, but the trouble is the join table is not directly accessible to your application.
Do instead...
class Cart < ApplicationRecord
has_many :cart_phone_links
has_many :phones, through: :cart_phone_links
end
class Phone < ApplicationRecord
has_many :cart_phone_links
has_many :carts, through: :cart_phone_links
end
class CartPhoneLink < ApplicationRecord
belongs_to :cart
belongs_to :phone
end
This gives you the same functionality as has_and_belongs_to_many but because the new table is actually a table accessible by rails you can add other fields ot it that give more information about the relationship, such as quantity
This is generally why has_many ... through: is considered more flexible than has_and_belongs_to_many

Ruby on rails simple relationship has_and_belongs_to_many

I have a simple rails app where I am trying to establish the relationship between two models.
I have a plan model and a subscription model.
A subscription will only ever have 1 plan but plans can belong to many subscriptions.
As there is no belong to many relationship I am guessing that the best way to create this is using has_and_belongs_to_many with a join table of plan_subscription - is this correct?
Assuming this is correct how do I ensure that my subscription only ever has a single plan created?
The current code I have is as follows:
class Subscription < ApplicationRecord
has_and_belongs_to_many :plans
end
class Plan < ApplicationRecord
has_and_belongs_to_many :subscriptions
end
Any help would be much appreciated.
has_and_belongs_to_many association is many to many association and you wrote subscription will only ever have 1 plan, plans can belong to many subscriptions so in this case your association is wrong.Your association will be like this:
class Plan < ActiveRecord::Base
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :plan
end

rails belongs_to has_many please explain

I have following:
User model with columns:
id user_id password created_at updated_at
Store model with columns:
id store_id store_name create_ad updated_at
Basically a user can belong to multiple stores. So I would want to get a query like "get all the stores that the user belongs to"
Relationships I've made are:
class User < ActiveRecord::Base
belongs_to :store, :foreign_key => "store_id"
end
class Store < ActiveRecord::Base
has_many :user, :foreign_key => "store_id"
end
are these correct?
Ultimately I want to find out whether a userid, password and storeid should be able to login.
So how can I use the find_byXXX on this ? so If I get a row back with passed in userid, password and storeId...I would know whether user should be able to login?
I noticed that belongs_to and has_many questions have been asked before but I was not able to understand well from those questions. maybe answers specific to my problem will help...
You're looking for a has_and_belongs_to_many relationship. Your tables and model should be as follows:
User Table:
id password created_at updated_at
Store Table:
id store_name created_at updated_at
Join Table (called stores_users):
store_id user_id
In your models:
class User < ActiveRecord::Base
has_and_belongs_to_many :stores
end
class Store < ActiveRecord::Base
has_and_belongs_to_many :users
end
To get a user's stores:
User.stores
See the rails API for more information.
It seems like you're making a lot of false assumptions about how ActiveRecords works on a basic level, so I would recommend reading the official and very straightforward ActiveRecord Associations guide.
So you've said that a user belongs to many stores. How many users belong to a single store?
If the answer is more than 1, then what you need is has_and_belongs_to_many and a third database table. The table will essentially contain pairs of (store_id, user_id).
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Although it is not required by Rails, it is recommended that you create a model for this relation and make the relation bidirectional on that model. You will thank yourself later.
class User < ActiveRecord::Base
has_many :userstores
has_many :stores, :through => :userstores
end
class Store < ActiveRecord::Base
has_many :userstores
has_many :users, :through => :userstores
end
class UserStore < ActiveRecord::Base
belongs_to :user
belongs_to :store
end

Resources