How to make a path to a paginated url?

北战南征 提交于 2020-01-06 13:04:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!