Associations in ruby on rails - ruby-on-rails

I have created a user using device authentication. I also have created article view, controller and model where model has fields such as title, body and article_id. Now I want to implement comments (with the condition that only logged in user can comment on an article). I have created an is_admin as a special user that has power create new articles through application.
The User table has all fields that are default generated by device. The Article table has fields like article_id, title, and body. There is still no association between user and article table. The Comment table will have (according to my understanding) comment_id, and comment_body.
Expected Associations:
class Comment < ActiveRecord::Base
belongs_to :article
belongs_to :user
I want to make sure that only logged in users can comment on articles, and that is_admin user can create new articles.
How can I create association between user, article and comment tables? Do I need to create association for user and comment table?

It is recommended to go through the rails guide and small blog to understand association as #dpassage suggested in comment. Looks you already have work around, so let me consolidate.
As you described, you will have three model:
First: User
class User
has_many :articles # not dependent => :destroy, may you not want to destroy article on deletion of user
has_many :comments, :dependent => :destroy
end
Second: Article
class Article
has_many :comments, :dependent => :destroy
belongs_to :user
end
Third: Comment
class Comment
belongs_to :user
belongs_to :article
end

Related

How do I delete records completely and partially from HABTM association

I have rails models Article and User which are associated with HABTM relation. ie an User can have many articles and an Article can belong to many User.
I am having hard time deleting the records. My requirement is:
If a user deletes article that is not associated with any other user, I want to delete the article completely, meaning, delete article from Article table as well as from all other tables that Article is associated with has_many association(I have other models like ArticleLinks, ArticleMetaTags etc that is associated with Article model).
If an Article is also associated with other User then dont delete the article completely. Just delete the User and Article association.
Thank you for your time and help.
You can always implement it in a before_destroy callback for ArticleUser (the join model):
class ArticleUser
belongs_to :article
belongs_to :user
after_destroy do
article.destroy if article.article_users.empty?
end
end
You need to create it, if you don't have one and change the has_and_belongs_to_many to has_many
class Article
has_many :article_users
has_many :users, through: :article_users
end
class User
has_many :article_users
has_many :articles, through: :article_users
end
That's a bit more code, but gives you more flexibility.
But I'd suggest implementing it in a some service class, something like:
class ArticleUsers::Delete
attr_accessor :article_user
def initialize(article_user)
self.article_user = article_user
end
def destroy
if article_user.destroy
article_user.article.destroy
end
end
end
And then call it anywhere you need as ArticleUsers::Delete.new(article_user).destroy
And as a precaution, you can add restrict_with_exception to article_users association in Article class, if you don't have any explicit logic for deleting an article. It causes an exception to be raised if there are any associated records.
class Article
has_many :article_users, dependent: :restrict_with_exception
end

How to get information from child table

I have a Users model with has_many :comments
Each comment records the current_user to the commenter column.
How can I call #commenter.username in my view and show the commenter's username?
Currently in comments_controller using: #commenter = User.find("2") will pull the correct information. I would like to use something along the lines of: #commenter = User.find_by_id(:commenter)
From the comments, it sounds like you have this Comment model:
class Comment < ActiveRecord::Base
belongs_to :user
end
The comment model represents comments on a user's page, where the user model is defined as:
class User < ActiveRecord::Base
has_many :comments
end
There is also a commenter column on the comments table to store the user who posted the comment (on the other user's page).
First, I would recommend using commenter_id for this column rather than commenter, since this is the convention for storing ids of any kind.
Assuming that you have a commenter_id column on the comments table, you would then define a second relationship as follows:
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commenter, class_name: "User", foreign_key: :commenter_id
end
The commenter relationship defines the user who wrote the comment, rather than the user whose page the comment is on.
For the other side of this relationship, update your User model:
class User < ActiveRecord::Base
has_many :comments
has_many :page_comments, class_name: "Comment", foreign_key: :commenter_id
end
Here, page_comments defines the comments this user has posted on other users' pages.
Then if you have a #comment, you can get the commenter's name with simply:
#comment.commenter.name
As long as you setup your column names and models correctly, dealing with getting information like this should be very simple.

Ruby on Rails has_many :through in a polymorphic association

I have searched and searched and found only partial solutions to my current question.
The thing is, I'd like to know if it is possible to use has_many :through along with a polymorphic association in Ruby on Rails.
I have a system where students can create travel plans (that can belong to many students) and refund claims (that can belong to only one student) for their projects. In this system, both admin users and students are able to comment on the plans and claims.
My associations are:
class Student < ActiveRecord::Base
has_and_belongs_to_many :travel_plans
has_many :refund_claims
has_many :comments, through: :travel_plans
has_many :comments, through: :refund_claims
end
class AdminUser < ActiveRecord::Base
has_many :comments
end
class TravelPlan < ActiveRecord::Base
has_and_belongs_to_many :students
has_many :comments, as: :commentable
end
class RefundClaim < ActiveRecord::Base
belongs_to :student
has_many :comments, as: :commentable
end
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
My questions are:
Is it correct to associate comments twice in the Student model?
I don't want the AdminUsers to have travel plans and refund claims, how can I identify their comments as being made on a travel plan or on a refund claim?
Would there be a better approach?
Thanks a lot in advance for everyone!
Cheers,
You probably want to add an polymorphic author attribute to the Comment model. Than you just need has_many :comments, as: :author to the Student and AdminUser model.
If this is a new application and you are starting on the green field you might want to rethink your models a bit and add a Role and a User model. Student would than be a role of user as would AdminUser be.
Is it correct to associate comments twice in the Student model?
No, not really. If you have duplicate association name, you can only use one of them. If you want to use both, you have to name them differently.

Adding another attribute to a many-to-many table in rails 3

I am currently using has_and_belongs_to_many to implement a many-to-many relationship. I would however want to put in a attribute in the many_to_many table.
Basically I am creating a email system. I have users and conversations. A user can have many conversations and a conversations can also have many users. However, I am trying to make it so that I can have a read/unread attribute to show which messages are read. Since conversations can have many users, it is not practicable to put the attribute in the conversations table as then it would mean that the conversation is read by all. So I think it would work best in the middle table. I am wondering though how I can access that attribute in the middle table. If the attribute is read. What code do I put in to access that and how do I update the attribute. As mention above I am using has_and_belongs_to_many
If you want to have additional attributes to your has-and-belongs-to-many association, you have to build a model class for that relation. See the detailed description in the Rails Guides about it.
After having read it for myself, this is now deprecated with the current version of Rails, so you really should switch to has_many :through. Your models could be (copied and changed from the Rails Guides, I don't know if connection is a good name for the m2n relation):
class User < ActiveRecord::Base
has_many :connections
has_many :conversations, :through => :connections
end
class Connection < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class Conversation < ActiveRecord::Base
has_many :connections
has_many :users, :through => :connections
end
There you are able to add additional attributes to your connections table, and refer in the code to them.

Rails: Should I use has_many :through?

I'm trying to figure out how to best way to create associations for the following models:
User
Category
Post
Comments
Here are the requirements I'm trying to meet:
A user can have many posts
A post belongs to a user
A post can have many comments
A comment belongs to a post
A post can belong to a category
A user does NOT have many categories.
(The number of categories is fixed and the same for all users)
A category can have many posts
In terms of routing, I'd like to be able to access a post within a certain category for a specific user. For example:
http://domain.com/users/1/categories/1/posts
Since there is no direct relationship between User and Category, I'm not quite sure how to best set up the associations. And I'm totally lost on how to configure the routes.
Here's what I have for my models:
class User < ActiveRecord::Base
has_many :posts
end
class Category < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :metric
has_many :comments
end
class Comments < ActiveRecord::Base
belongs_to :post
end
Is this a case where I should be using has_many :through relationships? Or something more complex like polymorphic associations? Thanks in advance!
Yes, it would be a very good idea to use :
User has_many :comments, :through => :posts
If you like, you can also get categories comments, by :
Category has_many :comments, :through => :posts
Remember that a through association is just a facility that allows you to do things like user.comments directly (and through is the way for the association to find the user comment that is referred to post model).

Resources