Rails. Virtual attribute (from a parent model) query - ruby-on-rails

I have three models: Account, Member and Child.
Member belongs to Account
Child belongs to Member
Member has an account_id attribute
Child does not have an account_id attribute
So I can do this...
Member.where(:account_id => current_user.account.id)
c = Child.last
c.member.account_id
In an index action, I want to list all Children that belongs to a particular account. I didn't want to add an extra account_id column to the children table.
Of course, I can't do this...
Child Model
def account_id
self.member.account_id
end
Children Controller
Child.where(:account_id => current_user.account.id)
Is there a way to list all children that belongs to particular account without having to add an account_id attribute?
By the way, I have this on the existing query...
#children = Child.search(params[:search]).order(sort_column + ' ' + sort_direction).page(params[:page]).per(10)

Starting from Child class, it could be done this way:
Child.includes(:member).where(:'members.account_id' => current_user.account.id)
This could be used to modify your existing query.

class Account < ActiveRecord::Base
has_many :members
#This is the line you were looking for
has_many :children, :through => :members
end
class Member < ActiveRecord::Base
belongs_to :account
has_many :children, :class_name => "Child"
end
class Child < ActiveRecord::Base
belongs_to :member
end
Now assuming you have an accounts instance you can access all of its children by:
account.children

Related

How can I modify the dependent: :destroy query for has_many relationship

I have a model called Family and it has a has_many relationship to Parent:
class Family < ActiveRecord::Base
has_many :parents, :dependent => :destroy
end
When a user deletes a Family, it should delete any associated Parent.
There's one major hitch: I have a multi-tenant environment (using the Apartment gem) and parents are in the public schema. Thus, I need to select only parents in the same account should be deleted.
Right now, when destroy is called on the Family I get:
SELECT "public"."users".* FROM "public"."users" WHERE "public"."users"."type" IN ('Parent') AND "public"."users"."family_id" = $FAMILY_ID
I need it to be:
SELECT "public"."users".* FROM "public"."users" WHERE "public"."users"."type" IN ('Parent') AND "public"."users"."family_id" = $FAMILY_ID AND "public"."users"."account_id" = $CURRENT_ACCOUNT_ID
Is there a way to override the Family.destroy method so that it only selects the right associated records?
Here's the solution I went with. I removed the dependent: :destroy clause from the has_many :parents relationship in the family.rb model. Instead, I perform the cascading delete in the Family controller's destroy action:
def destroy
#family = Family.find(params[:id])
authorize #family
parents = #family.parents.for_account(current_account.id)
#family.destroy
if #family.destroyed?
parents.destroy_all
end
redirect_to families_path
end
I had to do this in the controller because the controller is aware of the current_account while the model is not. The for_account method on the Parent model looks like this:
scope :for_account, -> (id) { where(:account_id => id) }

How to write active record query to details by using and

i have two tables
1)Properties :fields are id, name, propert_type,category_id
2)Admins : fields id, name,mobile,category_id
i want to write an active record to list all properties , where category_id in properties table and category_id in Admins table are equal, according to current_user_id
i am listing this property list by logging as admin.
model relation
class Category < ActiveRecord::Base
has_many :admins,dependent: :destroy
has_many :properties,dependent: :destroy
end
class Admin < ActiveRecord::Base
belongs_to :category
has_many :properties
end
class Property < ActiveRecord::Base
belongs_to :admin
belongs_to :category
end
i wrote active record like this , but i got error,
can anyone please suggest me a solution for this
#properties= Property.where('properties.category_id=?','admins.category_id=?').and('admins.id=?',current_user.specific.id)
With your assosciation,You can use a sub query for getting your result in one line
#properties = Property.where(category_id: Admin.select("category_id").where(id: current_user.id))
As per my understanding current_user is an Admin. So You can search by the category_id of current_user. If I'm right, try this
#properties = Property.where(category_id: current_user.category_id)

Having a many-to-many association in the same model rails

I have a model called User and for my model, a user can either be a Leader or a Member. In my user model i have this
class User < ActiveRecord::Base
attr_accessible :username, :type
end
I thought i could create a many-to-many association in the User model like this
class User < ActiveRecord::Base
attr_accessible :username, :type
has_and_belongs_to_many :users, :join_table => :team_members, :foreign_key => :team_leader_id
end
But i am not really sure how to go about it. So for example.
User 1 - type :leader
User 2 - type : member
User 3 - type: member.
I want to create a relationship that can show that User 1 is the leader of user 2 and user 3.
I am still a bit new to rails .
add leader_id to User
class User < ActiveRecord::Base
attr_accessible :username, :type
belongs_to :leader, class: User
has_many :members, class: User, foreign_key: :leader_id
end
use :
#user_1 = User.create(name: "Jhon")
#user_2 = User.create(name: "Tom", leader: #user_1)
#user_1.members
well, you have User table and user can be member or leader,
if you sure that there will not be any other roles
you can use boolean leader and can be true or false if false that mean this user is member
if you not sure if there may be any other roles
you can go with what you currently being used type column and can contain member or leader that is for the first part.
then you need leader to control many members then there is 2 possibilites:
Member can belongs to only 1 Leader then you will need to add a new column in user table called leader_id for example and in this case it will be
has_many :members, :class_name => "User", :foreign_key => :leader_id
Member can belongs to many leaders then you will need to create many to many relation and then will use a new table that contain leader_id and member_id and both should be refer to user table as a forigen keys.
And better than all and have this relation in User model and its only valid for Leader you can have 2 models that inherit from User and that is called STI Single Table Inheritance you can read more about it here:
class User < ActiveRecord::Base
# this type will be checked if Leader then its Leader model if Member then its Member model
self.inheritance_column = 'type'
end
class Member < User
end
class Leader < User
has_many :members, :class_name => "User", :foreign_key => :leader_id
end
this model is away better than all, and in this case let's say in your User model you have:
1 User type='Member'
2 User type='Leaeder'
if you say:
# will work
Member.find 1
User.find 1
# will fail as type is not Leader
Leader.find 1

Rails Multiple Parent Relationships

Three models:
User
List
Item
A User can have many Lists and a List can have many Items. Each List can have an Item added to it by ANY User. This means, for example, that you can create a list and I can add items to it. Make sense? Let's keep going.
I want to be able to find all Items created by X User at any point in time.
class User < ActiveRecord::Base
has_many :lists
has_many :items
end
class List < ActiveRecord::Base
belongs_to :user
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :list
belongs_to :user
end
I don't like this. It has a funky smell but I can't put my finger on it. I feel like there should be something better. When creating a new Item I would have to write something that looks like the following:
list = List.find(params[:list_id])
#item = list.items.new(params[:item])
user = User.first
#item.user = user
#item.save!
So, what am I missing? Are my relationships wrong (very likely)? Tell me! :)
It seems like there can be two different relationships between items and users: 1) items are added to lists by users, and 2) lists are created by users.
Only one user can create a list. Many users can add items to lists after they are created.
So modeling this requires two different relationships
class User < ActiveRecord::Base
has_many :lists
has_many :items_added, :class_name => "Item", :foreign_key => "added_by_user_id"
end
class List < ActiveRecord::Base
belongs_to :user
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :list
belongs_to :added_by_user, :class_name => "User", :foreign_key => "user_id"
end
It makes sense to assume that you all these relationships are required -- that is, a list needs a user_id when it's created to show who created it. Likewise, an item needs to record who added it to the list.
You'd need to add the added_by_user_id column to your items table to make this work and keep track of which user added the item.
So you could do this:
# To create a user and a list is easy!
user = User.create(user_params)
list = user.create_list(list_params)
# but when adding an item, you need to know which user is adding it
item = list.create_item({:added_by_user => current_user, :item_name => 'name', etc})
Now you can find all items added by a user using:
all_user_items = user.items_added
I haven't tested this and it's a bit complicated so I may have 1-2 mistakes in the code, but generally that's one way this could be modeled.

rails - preference form

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"

Resources