how to access data with has_many :through relation - ruby-on-rails-3

Hi I have three models: company, plan and subscription with following association
class Company < ActiveRecord::Base
has_one :plan, :through => :subscriptions
has_many :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :plan
belongs_to :company
end
class Plan < ActiveRecord::Base
has_many :subscriptions
has_many :companies, :through => :subscriptions
end
I have two plans in my application plan 'A' and plan 'B'. Plan 'A' is free and 'B' has some fee. Now i want to get companies registered with plan 'A' and companies with plan 'B'.
I want this data in my model, i know their is definitely a simple way to get all this but
every thing i have used i not giving me right data.any help would be thankful.

To get companies registered with plan 'A' and companies with plan 'B'.
Take object of plan, and then through following relationship code, you will get count of companies.
This is join concept.
eg. #plan is object of Plan 'A'.
then #plan.companies.count.
I suggest to use "polymorphic association" concept.

You need to insert new records through the association. Here is a related link that might help. how to add records to has_many :through association in rails
But a Pseudo-code will be like
1. You have a company object
2. you will have company.subscriptions
3. Insert new Plan objects in company.subscriptions
4. Save the data.
If you are still facing problem, I will try to add some code example.

Related

SQL relations in Rails. Trying to create two different references for one table relationship. Very confusing situation

I have a DB schema where a shipment belongs_to two users even though the relation is between model to model.
The shipment can have a receiver_id and a sender_id. Both the receiver & sender are two different records in the same table (the user model).
I was wondering how can I establish a relationship in my rails backend for a shipment to belong_to a record where the user is the sender as well as another record in the same DB where the user is the receiver.
I'v been thinking for ages how to do it, and its very hard to come up with a solution. The only solution I have is to destroy the existing User model, and create two different models: a receiver & a sender. Or is there another solution for this? I've attached my DB schema in this thread.
Any help would much appreciated. Thanks in advance!
DB Schema
class Shipment < ApplicationRecord
belongs_to :sender, :class_name => "User"
belongs_to :recipient, :class_name => "User"
end
class User < ApplicationRecord
has_many :sent_shipments, :class_name => "Shipment", foreign_key: 'sender_id'
has_many :received_shipments, :class_name => "Shipment", foreign_key: 'recipient_id'
end

Rails includes with where condition

I have two models:
user.rb
class User < ApplicationRecord
has_many :orders, inverse_of: :user, dependent: :restrict_with_exception
end
order.rb
class Order < ApplicationRecord
belongs_to :user, inverse_of: :orders
end
I am using includes with where like this:
User.where(id: selected_salesmen.pluck(:id))
.includes(:orders)
.where("order.booked_at > ? AND order.booked_at < ?",
booked_at_gteq,
booked_at_lteq)
However, it's not giving me required users with orders. Any explanation of why this isn't working?
This may be some confusing between the methods includes and joins, which have related, but very different meanings.
includes will eager-load related records, which prevents multiple database calls later on. It's mostly used for performance tuning.
joins will include a join to the related table in your database query, which allows you to build conditions based on the related model.
Note that, to use joins, you need to refer to the table name, not the relation name. By default, ActiveRecord will connect to a table which is the pluralised name of the model.
So, change includes to joins and 'order' to 'orders':
User.where(id: selected_salesmen.pluck(:id))
.joins(:orders)
.where(
"orders.booked_at > ? AND orders.booked_at < ?",
booked_at_gteq,
booked_at_lteq
)
You may also want to check that selected_salesmen.pluck(:id) returns some ids, too.

How to sub-query on the "many" part in a one-to-many association?

I have a standard one-to-many association in two models:
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
How do I query for messages that are last for users with name "John"?
I know I can use a joins to filter messages by user attributes. I am also convinced that the "last for that user" part of the query can be done with what is called an sql sub-query, but how exactly it is done is beyond me.
Message.joins(:user).where(users: {name: "John"}).<subquery?>

Preloading using includes on unrelated models

Suppose I have three models, set up something like this:
class Student < ActiveRecord::Base
has_many :tests
has_many :cars
end
class Car < ActiveRecord::Base
belongs_to :student
end
class Test < ActiveRecord::Base
belongs_to :student
end
I want to query all tests whose student does not have car. Preloaded.
I've tried the following:
Test.includes(:cars) # does not work because the two are not associated
Test.joins('inner join cars ON tests.student_id = cars.student_id') # works, but it doesn't preload the Cars model in my result
I'd prefer not to create a has_many :through relationship, because they really aren't related at all, but I'm not opposed to it if that's the best solution.
Thoughts?
Rails 4.1.5
PostgreSQL 9.3.4
ruby 2.1.2
A join across three tables is an inefficient way to do this. Rails might even be smart enough to realise this and split it into seperate db queries.
I would do it like this, which has two simple queries instead
student_ids_with_car = Car.select("student_id").distinct
#tests = Test.where("student_id not in (?)", student_ids_with_car)
You don't have to use has_many :through to associations and associations of those associations at the same time.
Test.includes(:student => :cars)
Will include student's and their cars (by default it will preload, you can force a joins based include by using eager_load instead of preload).

Is it okay to reference a third table in a many-to-many join table?

I am designing a relational database for projects and tasks. I want projects and tasks to be able to be classified or grouped by category.
If a project is shared by two or more users, I want each user to be able to categorize the project separately. Additionally, I want users to be able to share entire categories with each other, including all projects and tasks within that category. Therefore, here is the schema that I have come up with in terms of a basic ERD:
Here are my main models in Rails:
class User < ActiveRecord::Base
has_many :user_projects
has_many :user_categories
has_many :projects, :through => :user_projects
has_many :categories, :through => :user_categories
end
class Project < ActiveRecord::Base
has_many :user_projects
has_many :users, :through => :user_projects
has_many :tasks, :as => :taskable
end
class Task < ActiveRecord::Base
belongs_to :taskable, :polymorphic => true
end
class Category < ActiveRecord::Base
has_many :user_categories
has_many :users, :through => :user_categories
has_many :tasks, :as => :taskable
end
Is it okay to include a category_id foreign key in the User_Project join (junction) table like this? Also, do you see any problems with this schema in general? Any help will be greatly appreciated.
Since you asked if we saw any problems with the schema in general, ...,
The relationship between tasks and projects is not clear. If it's the taskable_id, that's a strange column name. Why not go with project_id?
There is also a lack of flexibility. You said that you want to allow users to share categories and your schema seems to support that. What I don't see is anything that allows two users to work on different tasks on the same project. That seems to be something that could happen in real life.
I'm puzzled about the User_Category table. Do categories apply to both users and projects?