Active Admin Querying on Association Tables Column presence and on its value - ruby-on-rails

I want to active admin filters on an admin panel page based on its column presence.
The model association is as follows:
class User < ActiveRecord::Base
has_many :objects, through: :orders
has_many :orders
end
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :object
end
class Object < ActiveRecord::Base
has_many :users, through: :orders
has_many :orders
end
An order has a quantity column in it.
I want to filter on index page of users in my admin pages which is integrated with active admin gem.
Ex: I want to filter as follows:
users with object quantity greater than 5.
I should check for association record presence and check for the quantities greater than 5 and only show that users.
I also need the negation filters as well.
I want to check for the users who don't buy an order.
I tried to use ransack:
For this, I need to add ransack search query for each object records. Is there any intuitive or any way I can achieve this functionality.

Related

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

How to Set Up Specific Active Record Association

I'm new to Rails and working with databases, and am wondering what the best way to set up the following Active Record Association would be.
I have the following tables:
user
product
request
I need each table to relate to the other tables in the following manner:
Every user should be able to have many products. Products will belong to users.
The products table needs to be associated with the user table in a way that no request is necessary to access product data through an association with user data
Every request needs to have two users, defined by foreign keys as requester and requestee
Every request also needs to have two products, defined as requester_product and requestee_product
I initially thought I could use a has_many :through association (seen here under 2.4: http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association), but this structure won't allow accessing product data through user data without the existence of a request.
class User < ActiveRecord::Base
has_many :requests
has_many :products
end
class Product < ActiveRecord::Base
has_many :requests
belongs_to :users
end
class Request < ActiveRecord::Base
belongs_to :requester, class_name: 'User'
belongs_to :requestee, class_name: 'User'
belongs_to :requester_product, class_name: 'Product'
belongs_to :request_product, class_name: 'Product'
end
I've assumed that multiple users can be associated with multiple products. Giving you:
user.products
product.user
request.requester # will return the relevant requesting user
request.requestee # will return the relevant requestee user
request.requester_product # will return the relevant requesting user's product
request.requestee_product # will return the relevant requestee user's product
product.requests # all requests associated to a product
user.requests # all requests associated to a user

How do I model this relationship for each unique user?

I am curious how I would go about implementing this.
I am creating an online learning website. There are a few courses on this website that users can complete. Courses have complete attribute which is just a boolean.
I want each user's progress to be trackable. So let's say I am at the course show page and I want to be able to do
#course.complete?
and get a unique response for each user.
Right now I have a user model set up which can log in and out, but I do not have a relationship between users and courses.
What the best way to set up this relationship so that each course is unique to each user?
i.e. if User A has complete the course then it will show true. If User B has not completed the course then it will show false.
Thanks!
I would do it like this
class Student < ActiveRecord::Base
has_many :course_enrollments
has_many :courses, :through => :course_enrollments
# code here
end
class Course < ActiveRecord::Base
has_many :course_enrollments
has_many :students, :through => :course_enrollments
# code here
end
class CourseEnrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
# code here
end

Rails User Membership Groups

I'm trying to make a application where a user belongs to multiple courses and multiple assignments belong to a course. I'm using devise for the user model. I want to be able to find all the courses a user belongs to and all the assignments their courses have.
User model:
has_and_belongs_to_many :course
has_many :assignments, :through => :courses
Course model:
has_and_belongs_to :user
has_many :assignments
Assignment model:
belongs_to :course
this requires an intermediate table CoursesUsers with columns user_id and course_id
and column course_id in Assignment
with this give you can do things like
current_user.courses
current_user.assignments
some_course.assignments
some_course.users
(assuming there is a current_user or some_course)
Read about details here: Active Record Associations Especially how to setup the has_and_belongs_to_many association

What is the best way to setup my tables and relationships for this use case?

1)A user can have many causes and a cause can belong to many users.
2)A user can have many campaigns and campaigns can belong to many users. Campaigns belong to one cause.
I want to be able to assign causes or campaigns to a given user, individually. So a user can be assigned a specific campaign. OR a user could be assigned a cause and all of the campaigns of that cause should then be associated with a user.
Is that possible? And could I set it up so that the relationships could be simplified like so:
User.causes = all causes that belong to a user
User.campaigns = all campaigns that belong to user whether through a cause association or campaign association
This should work.
class User < ActiveRecord::Base
has_many :causes, :through => :cause_users
has_many :campaigns, :through => :campaign_users
# other model stuff
class Cause < ActiveRecord::Base
has_many :users, :through => :cause_users
has-many :campaigns
# other model stuff
class Campaign < ActiveRecord::Base
belongs_to :cause
has_many :users, :through => :campaign_users
# other model stuff
class CampaignUser < ActiveRecord::Base
belongs_to :campaign
belongs_to :user
# other model stuff
class CauseUser < ActiveRecord::Base
belongs_to :cause
belongs_to :user
# other model stuff
has_many :through requires that you create a new model for each of these joins: campaign_users and cause_users, as is shown but it provides more functionality later on than has_and_belongs_to_many.
I would also suggest using better names than :campaign_users and :cause_users so the relationship is more meaningful.
I believe you should use the following:
class User < ActiveRecord::Base
has_and_belongs_to_many :causes
has_and_belongs_to_many :campaigns
end
class Cause < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :campaigns
end
class Campaign < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :cause
end
This way you can use
User.causes
User.campaigns
Cause.campaing
Cause.users
Campaign.users
Campaign.cause
You can read here about has_and_belongs_to_many relationship, here about has_one and here about belongs_to.
Let me know if this is what you want :]
Edit:
"I would still need User.campaigns to
be campaigns from a user's causes or
individual campaigns associated with a
user"
You can have a method on users model that returns all campaigns. Something like this:
def all_campaigns
self.campaigns + self.causes.collect{ |c| c.campaigns }
end
You can make :has_many :through associations between users and campaigns using a join model, and also between users and causes using the another join model. The you can make a :has_many :campaigns association in the causes model, putting a :belongs_to :cause in the campaign model.
But you won't be able to fetch all the users campaigns or causes by User.campaigns.orders or User.order.campaigns. You should make an iteration over the User.campaigns collection or User.causes, fetching Campaign.cause or Cause.capaigns. Or even making a custom SQL query, using joins and conditions to filter information in the joins.

Resources