问题
When user #1 likes/comments on user #2, user #2 gets a notification:
notifications/_notifications.html.erb
<%= link_to "", notification_path(notification.id), method: :delete, class: "glyphicon glyphicon-remove" %> <%= link_to Comment.find_by(notification.comment_id).user.name, user_path(Comment.find_by(notification.comment_id).user.id) %> commented on <%= link_to "your activity", (notification.activity_id) %>
but upon user #2 clicking the notification it doesn't lead anywhere since I removed the activity_path
, if I put it back before (notification.activity_id)
we get an error:
No route matches {:action=>"show", :controller=>"activities", > :id=>nil} missing required keys: [:id]
I don't know if this is possible, but upon clicking on the notification user #2 would be taken to the paginated page where the activity is. There are 20 activities per page via the gem will_paginate
so if the activity that was commented on is on page 2 then upon clicking on the activity, user #2 should be directed to: http://0.0.0.0:3000/activities?page=2
This would at least narrow down where the comment is on the activity feed for the user.
activities/index.html.erb
<% @activities.each do |activity| %>
<%= link_to activity.user.name, activity.user %>
<%= render "activities/#{activity.trackable_type.underscore}/#{activity.action}", activity: activity %>
<% activity.activity_likers.each do |user| %>
<%= user.name %>
<% end %>
<%= link_to like_activity_path(:id => activity.id), class: "btn", method: :post do %>
<span class='glyphicon glyphicon-thumbs-up'></span> Like
<% end %>
<%= render "comments/comments", comments: activity.comments %>
<%= render "comments/form", new_comment: Comment.new(commentable_id: activity.id, commentable_type: activity.class.model_name), create_url: :activity_comments_path %>
<% end %>
<%= will_paginate @activities %>
activities_controller.rb
class ActivitiesController < ApplicationController
def index
@activities = Activity.order("created_at desc").paginate(:page => params[:page], :per_page => 20)
end
def show
redirect_to(:back)
end
end
Please let me know if you need anymore code if you find that this is possible to do :)
UPDATE
class NotificationsController < ApplicationController
def index
@notifications = current_user.notifications
@notifications.each do |notification|
notification.update_attribute(:read, true)
activity = Activity.find(notification.activity_id) #Gives "Couldn't find Activity with 'id'=". I then removed ".activity_id" to see what happens next.
index = Activity.order(created_at: :desc).index(activity)
page_number = (index / per_page.to_f).ceil #I am then told "undefined local variable or method `per_page'" so I tried making it :per_page to which I then get: "undefined method `to_f' for :per_page:Symbol"
end
end
def destroy
@notification = Notification.find(params[:id])
@notification.destroy
redirect_to :back
end
end
routes.rb
resources :activities do
resources :comments
resources :notifications
member do
post :like
post :notifications
end
end
UPDATE #2
notifications/index.html.erb
<% if !@notifications.blank? %>
<%= render partial: "notifications/notification", collection: @notifications %>
<% else %>
<p>No notifications... yet</p>
<% end %>
comment.rb
class Comment < ActiveRecord::Base
after_create :create_notification
has_many :notifications
has_many :comment_likes
has_many :likers, through: :comment_likes, class_name: 'User', source: :liker
belongs_to :commentable, polymorphic: true
belongs_to :user
belongs_to :activity
private
def create_notification
@activity = Activity.find_by(self.activity)
@user = User.find_by(@activity.user_id).id
Notification.create(
activity_id: self.activity,
user_id: @user,
comment_id: self,
read: false
)
end
end
_create_notifications.rb
class CreateNotifications < ActiveRecord::Migration
def change
create_table :notifications do |t|
t.references :activity, index: true
t.references :comment, index: true
t.references :user, index: true
t.boolean :read
t.timestamps null: false
end
add_foreign_key :notifications, :activities
add_foreign_key :notifications, :comments
add_foreign_key :notifications, :users
end
end
回答1:
To determine on which page the activity
is located, you could do the following:
activity = Activity.find(notification.activity_id)
index = Activity.order(created_at: :desc).index(activity)
The above will determine the index
of the activity
within all of the activities.
So, let's say you've got 85 activities. You've got 20 activities per page, so in this case you would have 5 pages, right? Alright, let's assume the above index
returns 42. To calculate the page number you would have to do this (assuming that you've got a variable called per_page
which is 20):
page_number = (index / per_page.to_f).ceil
You've got index
42. Which you'll have to divide by the number of activities per page (it needs to be a float!), so that would be 20.0
. That results in 2.1
. ceil
that and you've got your page number, which would be 3.
So, to create the correct paginated path, you can now do this:
activities_path(page: page_number)
Update
Now that we know that the activity_id
isn't correctly set on the notification
we can fix that (also note that the comment_id
isn't set either). Change the last part of your Comment
model to this:
...
belongs_to :activity
validates :activity_id, presence: true
validates :user_id, presence: true
private
def create_notification
Notification.create(activity_id: self.activity_id, user_id: self.user_id, comment_id: self.id, read: false)
end
I've added two validations here to make sure the activity_id
and user_id
are set. Now as I said before the comment_id
isn't set either. That's because the id
is only assigned on save
, on create
you are just setting it up to be saved. So, change the after_create :create_notification
to after_save :create_notification
to be able to set the comment_id
as well.
That should set the activity_id
and comment_id
. Now for the next part. Getting the correct page number which should be added to the link in your _notification.html.erb
partial.
Add these methods to your Activity
class:
def page_number
(index / per_page.to_f).ceil
end
private
def index
Activity.order(created_at: :desc).index self
end
Now change the path in your notifications/_notification.html.erb
partial to:
activities_path(page: notification.activity.page_number)
Note: If you get an error about the per_page
in the page_number
method you probably haven't set the value per_page
in the model itself (like this; Basically add self.per_page = 20
to your model right below class Activity < ActiveRecord::Base
)
If you decide to do it like this, you can remove the , :per_page => 20
part in your ActivitiesController
. If not, simply replace per_page.to_f
with 20.to_f
or 20.0
.
Also, remove the 3 lines from your NotificationsController
which you've commented out previously to find out whether the activity_id
was set or not. You don't need them anymore, since we've placed them in the Activity
class.
来源:https://stackoverflow.com/questions/30134662/how-to-make-a-path-to-a-paginated-url