How to associate models? - ruby-on-rails

I am building a ROR app with Users and Groups and I want to be able to link them with an associative model called Memberships.
My problem is that when I try to create a group with one member, the members array for the new group is always empty.
I tried creating a group like this:
def create (user)
#group = Group.new(create_group_params)
user.join(#group)
user.save
#group.save
end
but #group.members is empty when I print it out. How can I make the user a member of the group?
Here are my models:
Group.rb
class Group < ActiveRecord::Base
has_many :passive_memberships, class_name: "Membership",
foreign_key: "club_id",
dependent: :destroy
has_many :members, through: :passive_memberships, source: :member
end
User.rb
class User < ActiveRecord::Base
has_many :active_memberships, class_name: "Membership",
foreign_key: "member_id",
dependent: :destroy
has_many :memberships, through: :active_memberships, source: :club
def join(group)
active_memberships.create(club_id: group.id)
end
end
Membership.rb
class Membership < ActiveRecord::Base
belongs_to :member, class_name: "User"
belongs_to :club, class_name: "Group"
validates :member_id, presence: true
validates :club_id, presence: true
end

Oh. I have to save the group before the user can join it.
def create (user)
#group = Group.new(create_group_params)
#group.save
user.join(#group)
user.save
end

Related

Gem `activity_notification` does not create a new record after getting triggered by an active record

The gem activity_notification is not creating/triggering after I've configured it according to the documentation. I've tried to create the notification in the event of a user creating a comment or replying to an existing comment, but the gem is not created/triggered. Please help me figure out why.
Here's my code
Model User
class User < ApplicationRecord
audited
with_options dependent: :destroy do |assoc|
assoc.has_many :forums, class_name: 'Communication::Forum'
assoc.has_many :favorited_forums, class_name: 'Communication::FavoritedForum'
assoc.has_many :comments
assoc.has_many :likes
end
acts_as_target
end
Model Forum
class Communication::Forum < ApplicationRecord
audited
belongs_to :user
acts_as_commentable
has_many :likes, as: :likeable
has_many :favorited_forums, class_name: "Communication::FavoritedForum"
end
Model Comment
class Comment < ActiveRecord::Base
audited
acts_as_nested_set scope: [:commentable_id, :commentable_type]
belongs_to :commentable, polymorphic: true
acts_as_notifiable :users,
targets: ->(comment, key) {
([comment.commentable.user] + [comment.user]).uniq
}
end

Rails 5.1, models and db relation, share datas with groups of users

sorry for the title I didn't really know what to put in there to be really clear. So I'll be clear in my explanation.
Users can create Groups and Links via form. The users can join Groups via Member where member has group_id and user_id in the table. I would like to be able to share the Users Link within the group.
So when a user creates a group, other users join this group. And for now when a user creates a link, it's only for himself but I want the user to be able to share (or not) the links he created with the groups he is part of. If the user is a member of several groups then the user can choose in which group he wants to share the link he created.
I have 4 models : Link.rb, User.rb, Member.rb and Group.rb. Here are my relations :
#Link.rb:
class Link < ApplicationRecord
belongs_to :user
end
#User.rb :
class User < ApplicationRecord
has_many :links, dependent: :destroy
has_many :members, :dependent => :destroy
has_many :groups, :through => :members
end
#Member.rb :
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
validates :user_id, :presence => true
validates :group_id, :presence => true
validates :user_id, :uniqueness => {:scope => [:user_id, :group_id]}
end
#Group.rb :
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
def to_param
auth_token
end
end
What I tried :
I added a reference of group_id in the link table. And added belong_to :group in link.rb, and has_many :links, dependent: :destroy in group.rb.
In my new link form I added the current_user group_id in a select (to retrieve only the groups where the user is in) and on create the link is created with the group_id and the current_user id. That works.
Problem is that I have to enter a group_id which means I give no choice to the user and he has to give a group_id so basically he must share the link to the group. Which is not what I want.
What I thought about :
Maybe I should just go for the same idea as I did for members. Which means having a new table like grouplinks where I give the group_id, link_id and the user_id with relations in place so I can use the grouplink.id to share in my group or not. Is this a good option ? If yes what are the relations I should put in place ? Any other suggestion, maybe I'm completly wrong and there is something easy to do and I don't see it.
I will try to give a shot with some code I thought about :
#Link.rb:
class Link < ApplicationRecord
belongs_to :user
belongs_to :grouplink
end
#User.rb :
class User < ApplicationRecord
has_many :links, dependent: :destroy
has_many :grouplinks, dependent: :destroy
has_many :members, :dependent => :destroy
has_many :groups, :through => :members
end
#Grouplink.rb :
class Member < ApplicationRecord
belongs_to :user
belongs_to :group
belongs_to :link
end
#Group.rb :
class Group < ApplicationRecord
has_secure_token :auth_token
has_many :members, :dependent => :destroy
has_many :users, through: :members, source: :user
belongs_to :owner, class_name: "User"
has_many :groupslinks, :dependent => :destroy
has_many :links, through: :grouplinks
def to_param
auth_token
end
end
Could that work out ?
Thanks for your help.
It's better to create a join table with group_id and link_id. Since the Group Admin is the user who created the group, you don't even need to add user_id(member_id I suppose) since every member of that group can access the link. Get the user groups and add that link to that particular group and check the association.
class GroupLink
belongs_to :group
belongs_to :link
You can just do
#group = #user.groups.find(params[:group_id])
#group_link = #group.group_links.build(link_id: link_id)
#group_link.save
Let me know if you need anything else or clarify this.

How to create a scope for current_user.following?

Here are my User and Relationships models
class User < ActiveRecord::Base
has_many :active_relationships, class_name: "Relationship",
foreign_key: "follower_id",
dependent: :destroy
has_many :passive_relationships, class_name: "Relationship",
foreign_key: "followed_id",
dependent: :destroy
has_many :followers, through: passive_relationships, source: :follower
has_many :following, through: :active_relationships, source: :followed
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User", counter_cache: :followeds_count
belongs_to :followed, class_name: "User", counter_cache: :followers_count
validates :follower_id, presence: true
validates :followed_id, presence: true
validates :followed, uniqueness: { scope: [:follower, :followed] }
end
In Users Controller I can do:
#users = current_user.following
However I would like to turn this into a scope in my User model.
There are 2 things you may approach:
Find all users who are following someone
class User < ActiveRecord::Base
scope :following_to, -> (user_id) {
where(
"id IN ( SELECT followed_id
FROM relationships
WHERE follower_id = ?
)",
user_id
)
}
end
Find all users who are following anyone, that means they are a follower
class User < ActiveRecord::Base
scope :follower, -> {
where("id IN ( SELECT followed_id FROM relationships)")
}
end
Finally, you can use these scope as your expectation:
# Find all users who are following to User (id = 1)
User.following_to(1)
# Find all users who are following someone,
# aka they are a follower
User.follower
By using the Instance Method you can make a method For User Model
like this :
class User < ActiveRecord::Base
def following?
self.following.present?
end
end
By Using Scope you can call only the activerecord based query into the scope of model.
You should get also this way
scope :following?, lambda { |user|
{ user.following.present? }
And this should be call like in your controller
User.following?(current_user)

Rails has_many :through with the where clause

I've built easy Twitter application in Rails.
Now I would like to choose three random users that are not followed by the current user.
Here is my model:
class User < ActiveRecord::Base
has_many :tweets, dependent: :destroy
has_many :followerships, class_name: 'Followership', foreign_key: 'followed_id'
has_many :followedships, class_name: 'Followership', foreign_key: 'follower_id'
has_many :followers, through: :followerships, source: :follower
has_many :followed, through: :followedships, source: :followed
end
class Followership < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
end
class Tweet < ActiveRecord::Base
belongs_to :user
end
I tried to use the following query:
User.where.not(followers: current_user).order("RANDOM()").limit(3)
But it obviously doesn't work as I get no such column: users.follower_id error.
Is it even possible to do without sql query?
Thank you!
Try this:
already_following = current_user.followed.map(&:id)
#users = User.where.not(id: already_following).order("RANDOM()").limit(3)
Basically what I did, was got the list of users already being followed. Then you check the User table for id's not matching users already being followed.

Designing Two Models to Have A Complex Association

I have two tables, users and groups. An user owns a group and can be apart of multiple groups. A group belongs to one user and can have many users.
Thus for my user model I have
has_and_belongs_to_many :groups
has_many :groups
While for my group model I have
has_and_belongs_to_many :users
belongs_to :user
I also have a join table in my migrations..
def change
create_table :groups_users, :id => false do |t|
t.integer :group_id
t.integer :user_id
end
end
My question is does this make sense? I feel like I'm doing something wrong by having has_many and belongs_to on top of has_and_belongs_to_many.
The way I would approach this, and this is my own personal methodology, is with 3 tables/models like so:
group_user.rb
class GroupUser < ActiveRecord::Base
attr_accessible :user_id, :group_id
belongs_to :group
belongs_to :user
end
group.rb
class Group < ActiveRecord::Base
attr_accessible :owner_id
validates_presence_of :owner_id
has_many :group_users
has_many :users, through: :group_users
end
user.rb
class User < ActiveRecord::Base
attr_accessible :some_attributes
has_many :group_users
has_many :groups, through: :group_users
end
Then, whenever you create a Group object, the User that created it would have its id placed in the owner_id attribute of Group and itself into the GroupUser table.
Another option, so as to not have multiple foreign keys pointing to the same relationship, is to use a join model and then add a flag on the join model to denote if the user is the owner.
For example:
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, through: :memberships
has_many :owned_groups, through: memberships, conditions: ["memberships.owner = ?", true], class_name: "Group"
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
#This model contains a boolean field called owner
#You would create a unique constraint on owner, group and user
end
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships
has_one :owner, through: :memberships, conditions: ["memberships.owner = ?", true], class_name: "User"
end

Resources