1

Dans mon application, j'ai un système de commentaires qui est largement basé sur ce railscast. Maintenant, dans mes modèles, je change le to_param en une chaîne aléatoire de sorte que l'identifiant ne soit pas dans l'URL. Mais alors ça casse commentant.Rails polymorphe commentant avec permalink/token urls

status.rb

class Status < ActiveRecord::Base 
    attr_accessible :content, :member_id, :document_attributes, :permalink 
    belongs_to :member 
    belongs_to :document 
    has_many :comments, as: :commentable, dependent: :destroy 

    before_create :make_it_permalink 

    accepts_nested_attributes_for :document 

    def to_param 
     permalink 
    end 

    private 

    def make_it_permalink 
     # this can create permalink with random 12 digit alphanumeric 
     self.permalink = SecureRandom.hex(12) 
    end 

end 

statuses_controller.rb

class StatusesController < ApplicationController 

before_filter :authenticate_member!, only: [:index, :new, :create, :destroy] 
before_filter :find_member 

rescue_from ActiveRecord::RecordNotFound do 
    render file: 'public/404', status: 404, formats: [:html] 
end 

def index 
    @statuses = Status.order('created_at desc').page(params[:page]).per_page(21) 
    respond_to do |format| 
     format.html # index.html.erb 
     format.js 
    end 
end 

def show 
    @status = Status.find_by_permalink(params[:id]) 
    @commentable = @status 
    @comments = @commentable.comments.order('created_at desc').page(params[:page]).per_page(15) 
    @comment = @commentable.comments.new 
    respond_to do |format| 
     format.html # show.html.erb 
     format.json { redirect_to profile_path(current_member) } 
    end 
end 

def new 
    @status = Status.new 
    @status.build_document 

    respond_to do |format| 
     format.html # new.html.erb 
     format.json { render json: @status } 
     format.js 
    end 
end 

def create 
    @status = current_member.statuses.new(params[:status]) 

    respond_to do |format| 
     if @status.save 
     @activity = current_member.create_activity(@status, 'created') 
     format.html { redirect_to :back } 
     format.json 
     format.js 
     else 
     format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' } 
     format.json { render json: @status.errors, status: :unprocessable_entity } 
     format.js 
     end 
    end 
end 

def destroy 
    @status = current_member.statuses.find(params[:id]) 
    @activity = Activity.find_by_targetable_id(params[:id]) 
    @commentable = @status 
    @comments = @commentable.comments 
    if @activity 
     @activity.destroy 
    end 
    if @comments 
     @comments.destroy 
    end 
    @status.destroy 

    respond_to do |format| 
     format.html { redirect_to profile_path(current_member) } 
     format.json { head :no_content } 
    end 
end 

private 

def find_member 
    @member = Member.find_by_user_name(params[:user_name]) 
end 

def find_status 
    @status = current_member.statuses.find_by_permalink(params[:id]) 
end 

end 

comments_controller.rb

class CommentsController < ApplicationController 

before_filter :authenticate_member! 
before_filter :load_commentable 
before_filter :find_member 

def index 
    redirect_to root_path 
end 

def new 
    @comment = @commentable.comments.new 
end 

def create 
    @comment = @commentable.comments.new(params[:comment]) 
    @comments = @commentable.comments.order('created_at desc').page(params[:page]).per_page(15) 
    @comment.member = current_member 
    respond_to do |format| 
     if @comment.save 
     format.html { redirect_to :back } 
     format.json 
     format.js 
     else 
     format.html { redirect_to :back } 
     format.json 
     format.js 
     end 
    end 
end 

def destroy 
    @comment = Comment.find(params[:id]) 
    respond_to do |format| 
     if @comment.member == current_member || @commentable.member == current_member 
     @comment.destroy 
     format.html { redirect_to :back } 
     format.json 
     format.js 
     else 
     format.html { redirect_to :back, alert: 'You can\'t delete this comment.' } 
     format.json 
     format.js 
     end 
    end 
end 

private 

# def load_commentable 
#  resource, id = request.path.split('/')[1,2] # photos/1/ 
#  @commentable = resource.singularize.classify.constantize.find(id) # Photo.find(1) 
# end 

# alternative option: 
def load_commentable 
    klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] } 
    @commentable = klass.find(params["#{klass.name.underscore}_id"]) 
end 

#def load_commentable 
# @commentable = params[:commentable_type].camelize.constantize.find(params[:commentable_id]) 
#end 

def find_member 
    @member = Member.find_by_user_name(params[:user_name]) 
end 

end 

T Le problème réside dans la méthode load_commentable dans le comments_controller. J'ai essayé quelques variantes de la méthode, mais la seconde fonctionne mieux pour mon application et elle fonctionnait quand l'URL contenait leurs identifiants. Mais depuis que j'ai écrasé le to_param pour utiliser mon permalien aléatoire, le commentaire a cessé de fonctionner parce qu'il essaie de trouver le id où il est égal à permalink. Comme il semble essayer de trouver l'ID via l'URL, comment puis-je passer l'ID réel et non le permalien ou comment puis-je trouver commentable par son permalien au lieu de l'ID?

Répondre

1

Il est difficile de dire si votre param sera toujours la valeur de id ou toujours le permalien, ou sera parfois un identifiant et parfois un permalien.

Si ce sera toujours un lien permanent, puis faites:

@commentable = klass.find_by_permalink(params["#{klass.name.underscore}_id"]) 

au lieu de

@commentable = klass.find(params["#{klass.name.underscore}_id"]) 

S'il est parfois id et parfois d'autres, alors vous aurez besoin faire logique pour déterminer qui est nécessaire en fonction de la classe.

+0

Merci. Cela fonctionne à nouveau correctement, ils seront toujours un permalien donc c'est ce dont j'avais besoin. – iamdhunt