Rails - Querying Noticed Notification with the params id - ruby-on-rails

I have searched through the related questions for example this one and the solutions marked there doesn't work for me.
So here is my problem:
I want to get a list of notifications that are for a specific recipient, and the notifications have to be made on comments belonging to a specific plant.
Currently I am using ruby to filter but the database hit is not ideal.
Here is the state of my code.
Models:
class Plant < ApplicationRecord
has_many :comments
end
class User < ApplicationRecord
has_many :notifications, as: :recipient, dependent: :destroy
end
class Notification < ApplicationRecord
belongs_to :recipient, polymorphic: true
end
class Comment < ApplicationRecord
has_noticed_notifications
end
class CommentNotification < Noticed::Base
def comment
params[:comment]
end
end
This is the query I am currently using: #plant.comments.flat_map { |comment| comment.notifications_as_comment }.filter { |notification| notification.recipient == current_user }.map(&:mark_as_read!)
Any help is deeply appreciated...

I resolved this by making a comment method and then using that in my filter, it also killed all the excess dB hits I was getting.
def comment_id
self[:params][:comment].id
end
Then I used this query to arrive at the result, looks cleaner too. Note comment_ids = #plant.comments.ids
Notification.unread.where(recipient_id: current_user.id)
.filter { |notification| comment_ids.include?(notification.comment_id) }
.map(&:mark_as_read!)

Noticed has a built in helper method for finding notifications based on the params.
If you add has_noticed_notifications to the model which you want to search for in the params, Comment in your case.
You can then call #comment.notifications_as_comment and it will return all notifications where the #comment is params[:comment]
This is in the Noticed readme here. I definitely came here and found this question before I found the details in the readme!

Related

Cannot modify association ":has_many." using Ruby on rails

I'm working with three tables as follows:
article.rb
class Article < ActiveRecord::Base
has_many :comments
has_many :comentarios, :through => :comments
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :article
has_many :comentarios
end
and comentario.rb
class Comentario < ActiveRecord::Base
belongs_to :article
end
Everything works fine until I attempt to add a 'comentario' and returns this error
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection in ComentariosController#create
Cannot modify association 'Article#comentarios' because the source reflection class 'Comentario' is associated to 'Comment' via :has_many.
This is the code I use to create a new 'comentario'
comentarios_controller.rb
class ComentariosController < ApplicationController
def new
#comentario = Comentario.new
end
def create
#article = Article.find(params[:article_id])
#comentario = #article.comentarios.create(comentario_params)
redirect_to article_path(#article)
end
private
def comentario_params
params.require(:comentario).permit(:comentador, :comentario)
end
end
The output returns an error in the line where I create #comentario from calling #article but I can't see why since Ruby documentation says that once I associate comentario to article using :through, I can simply call something like #article.comentario.
Any idea of what is causing this error?
or do you have any suggestion on how to achieve this association in any other way?
Ok. The issue is that Rails is confused about which article to use here.
Your Comment model belongs_to :article but also your Commentario belongs_to :article... so if you use #article.commentarios - it's confused as to whether the article refers to the article of the comment or the article of the commentario.
You will probably need to update your form to be more explicit about what you're referring to. A form for the commentario should actually include fields for the comment it creates.
Somebody else had the same problem here. You may wish to look at the solution here: "Cannot modify association because the source reflection class is associated via :has_many"

How to call instance method of comment class through Article Model ?

class Comment < ActiveRecord::Base
belongs_to :article
end
class Article < ActiveRecord::Base
has_many :comments do
def posted_comments
#user_comment is just an attribute of comment.
collect(&:user_comment)
end
end
end
to fetch the posted comments :
Article.first.comments.posted_comments
=> ["Nice article posted", "comment 2 added", "Good article"]
Above one is fetching correct results, but I want to have a more compact version.
Something like this:
Article.first.posted_comments
#this should list the collection of comments on the article.
Can we do something like this with Rails ActiveRecord ?
For simply solution, you can define method called posted_comments that calls nested association as the following:
def posted_commments
self.comments.posted_comments
end
Or, Try the following code:
has_many :posted_comments, -> { select("user_comment") }, class_name: "Comment"

How can I add custom vote buttons to a rails app

So here is an idea
class Question < ActiveRecord::Base
has_many : answers
end
class Answer < ActiveRecord::Base
belongs_to :question
has_one :vote
end
class Vote < ActiveRecord::Base
belongs_to :question
end
How can i limit the number of questions a user can ask?
Is there a better way of this?
Answer to the first question:
Inside of the QuestionsController create method, you should just put some code that says something like:
if user.questions.length > 3
#tell them they can't ask more questions
else
#create the question
end
to the second:
Also, I don't think it makes sense to have Vote be it's own resource. I would just define 'vote' or 'votes' as a field on Answer. When an answer gets voted for, you just increment Answer.votes. Depends on your use case though
Beyond, if you want to customize more in depth your validation, you can delegate the validation as so, assuming the user_id is the user column nested in the question model
class Question < ActiveRecord::Base
validates_with LengthValidator, :field => :user_id
....
end
class LengthValidator < ActiveModel::Validator
def validate(record)
if options[:fields].any?
#put the above conditional of #Accipheran
end
end

accessing associations within before_add callback in Rails 3

In Rails 3.2 I have been looking for a way to traverse the associations of an object within the before_add callback.
So basically my use case is:
class User < ActiveRecord::Base
has_and_belongs_to_many :meetings
end
class Meeting < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :comments, :before_add => :set_owner_id
end
class Comment < ActiveRecord::Base
belongs_to :meeting
end
def set_owner_id(child)
child.owner_id = <<<THE USER ID for #user >>>
end
and I am creating a comment within the context of a user:
#user.meetings.first.comments.create
How do I traverse the associations from within the before_add callback to discover the id of #user? I want to set this at model level. I have been looking at proxy_association, but I may be missing something. Any ideas?
You should probably create the comment in the context of the meeting, no? Either way, you should handle this in the controller since you'll have no access to #user in your model.
#comment = Meeting.find(id).comments.create(owner_id: #user, ... )
But if you insist on your way, do this:
#comment = #user.meetings.first.comments.create(owner_id: #user.id)

Retrieve all posts where the given user has commented, Ruby on Rails

I have users, posts and comments. User can post only one comment to each post.
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
class Post < ActiveRecord::Base
has_many :comments
belongs_to :user
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
On userpage (http://host/users/1 for example) I want to show all posts where the given user has commented. Each post then will have all other comments.
I can do something like this in my User controller:
def show
#user = User.find(params[:user_id])
#posts = []
user.comments.each {|comment| #posts << comment.post}
end
This way I will find User, then all his comments, then corresponding post to each comment, and then (in my view) for each post I will render post.comments. I'm totally new in Rails, so I can do this =) But I think it's somehow bad and there is a better way to do this, maybe I should use scopes or named_scopes (don't know yet what this is, but looks scary).
So can you point me out to the right direction here?
You could define an association which retrieves all the posts with comments in a single query. Keeping it in the model reduces the complexity of your controllers, enables you to reuse the association and makes it easier to unit test.
class User < ActiveRecord::Base
has_many :posts_with_comments, :through => :comments, :source => :post
# ...
end
:through is an option for has_many to specify a join table through which to perform the query. We need to specify the :source as Rails wouldn't be able to infer the source from :post_with_comments.
Lastly, update your controller to use the association.
def show
#user = User.find(params[:user_id])
#posts = #user.posts_with_comments
end
To understand more about :through and :source take a look at the documentation.
When you got the user, you have the associations to his posts and each post has his comments.
You could write:
(I don't know the names of your table fields, so i named the text text)
# In Controller
#user = User.find(params[:user_id]).include([:posts, :comments])
# In View
#user.posts.each do |post|
post.text
# Comments to the Post
post.comments.each do |comment|
comment.text
end
end
I haven't tested the code, so there could be some errors.

Resources