7

config/routes.rb:

resources :posts do
  resources :comments
end

resources :pictures do
  resources :comments
end

コメントできる内容をもっと増やしていきたいです。

私は現在mongoidを使用しています(mongomapperはまだRails 3と互換性がありません)。コメントは埋め込みリソースです(mongoidはまだポリモーフィックリレーショナルリソースを処理できません)。つまり、親リソースが必要ですコメントを見つけるためです。

次の問題のいくつかを処理するエレガントな方法はありますか?

私のコントローラーでは、コメントを見つける前に親を見つける必要があります。

if params[:post_id]
  parent = Post.find(params[:post_id]
else if params[:picture_id]
  parent = Picture.find(params[:picture_id]
end

コメント可能なものをさらに追加し始めると、面倒になります。

またurl_for([comment.parent, comment])、機能しないため、モデルで何かを定義する必要がありますが、モデルでインデックスルートを定義する必要があるだけでなく、編集および新しいルート定義Commentを定義する必要があると思います.Comment

先に進むにつれて、対処しなければならない問題が増える可能性があります。

私がこの問題を解決しようとした最初の人だとは想像できません。これをより管理しやすくするための解決策はありますか?

4

3 に答える 3

4

私は自分のアプリで似たようなことをしなければなりませんでした。思いついたものを少し変更しましたが、テストしていないので、注意して使用してください。きれいではありませんが、私が考えた何よりも優れています。

routes.rb で:

resources :posts, :pictures

controller :comments do
  get '*path/edit' => :edit, :as => :edit_comment
  get '*path'      => :show, :as => :comment
  # etc. The order of these is important. If #show came first, it would direct /edit to #show and simply tack on '/edit' to the path param.
end

comment.rb で:

embedded_in :commentable, :inverse_of => :comments

def to_param
  [commentable.class.to_s.downcase.pluralize, commentable.id, 'comments', id].join '/'
end

comments_controller.rb の before フィルター:

parent_type, parent_id, scrap, id = params[:path].split '/'

# Security: Make sure people can't just pass in whatever models they feel like
raise "Uh-oh!" unless %w(posts pictures).include? parent_type

@parent = parent_type.singularize.capitalize.constantize.find(parent_id)
@comment = @parent.comments.find(id)

わかりました、醜さは終わりました。これで、必要なモデルにコメントを追加して、次のようにするだけです。

edit_comment_path @comment
url_for @comment
redirect_to @comment

等々。

編集:必要なのは編集と更新だけだったので、自分のアプリに他のパスを実装しませんでしたが、次のようになると思います:

controller :comments do
  get    '*path/edit' => :edit, :as => :edit_comment
  get    '*path'      => :show, :as => :comment
  put    '*path'      => :update
  delete '*path'      => :destroy
end

他のアクションはよりトリッキーになります。おそらく次のようなことをする必要があります:

  get  ':parent_type/:parent_id/comments'     => :index, :as => :comments
  post ':parent_type/:parent_id/comments'     => :create
  get  ':parent_type/:parent_id/comments/new' => :new,   :as => :new_comment

次に、params[:parent_type] と params[:parent_id] を使用してコントローラーの親モデルにアクセスします。URL ヘルパーに適切なパラメーターを渡す必要もあります。

comments_path('pictures', 7)
于 2010-09-10T01:15:50.223 に答える
2

Ryan Bates はRailscasts #154でポリモーフィック アソシエーションについて説明しましたが、例は Rails 2 と Active Record のものでした。いくつかの変更を加えることで、Rails 3 と Mongoid を使用して彼の例を機能させることができました。

Post および Picture モデルで、次の行を追加します。

embeds_many :comments, :as => :commentable

Mongoid 関連付けのドキュメント によると、すべてのembedded_in関連付けは多態的です。コメントはコメント可能の子であるため、Mongoid を使用する場合、Railscast で言及されている列と列commentable_idは必要ありません。commentable_typeComment モデルに、次の行を追加します。

embedded_in :commentable, :inverse_of => :comment

次のように config/routes.rb でルートをセットアップします。

resources posts do
  resources comments
end

resources pictures do
  resources comments
end

次のメソッドをコメント コントローラーにprivateメソッドとして追加します。これは Ryan の方法と同じです。

def find_commentable  
  params.each do |name, value|  
    if name =~ /(.+)_id$/  
      return $1.classify.constantize.find(value)  
    end  
  end  
  nil  
end

コメントを見つける必要がある各コメント コントローラー アクションで、最初に find_commentable メソッドを呼び出して親を取得します。親が見つかったら、コメント可能なコメントを検索して、ID でコメントを見つけることができます。たとえば、編集アクションでコメントを見つけるコードは次のようになります。

@commentable = find_commentable  
@comment = @commentable.comments.find(params[:id])

すべてのアクションの開始時に find_commentable を呼び出す繰り返しを減らすために、次のようにコントローラーの上部に before フィルターを配置できます。

class CommentsController < ApplicationController
  before_filter :find_commentable
  ...

そして、find_commentable メソッドの return 呼び出しを次のように変更します。

return @commentable = $1.classify.constantize.find(value)

この方法で問題は発生していませんが、問題が発生した場合はご指摘ください。

于 2010-12-23T04:45:54.470 に答える
0

Uriptical の回答を利用して、関係は機能することがわかりましたが、名前付きルートはまだ機能しませんでした。

私はまだ Rails 3 に慣れていませんが、eval を使用して簡単な解決策を見つけました。

たとえば、私のプロジェクトでは、ポリモーフィックな親 (私のアプリではモンゴイド オブジェクト Product および Category として表されます) は、find_comentable の変更を使用して @imagable として定義され、編集中の子は @image として参照されます。

product_image_path(@imagable, @image)which do のような URL は、次のGET => products/:product_id/images/ように置き換えることができます。

send("#{@imagable.class.name.downcase}_image_url", @imagable, image )

これは、すべての名前付きパスで機能します。例えば:

link_to 'Edit', send("edit_#{@imagable.class.name.downcase}_image_path", @imagable, image ) 
link_to 'Destroy', send("#{@imagable.class.name.downcase}_image_url", @imagable, image), :confirm => 'Are you sure?', :method => :delete

これの欠点は、リダイレクトがある場所ならどこでも、ビュー全体とコントローラーに送信が残ることです。

ルート経由でこれを行うためのよりエレガントなソリューションはありますか?

* eval を send に置き換え

于 2011-01-29T23:43:43.477 に答える