2009-09-06 2 views
2

여러 모델 (예 : A, B)이 다형성으로 설명 모델과 연결되어있는 앱을 만들었습니다. 컨트롤러와 연관된 페이지를 볼 때 액션을 표시하면 A 객체와 관련된 주석이 새 객체를 생성하는 양식과 같이 표시됩니다. 이 모든 것은 작동하며 레일 웹 사이트에 게시 된 Ryan Bates의 15 분 블로그와 비슷합니다. 그러나 사용자가 빈 주석을 제출하지 않도록하기 위해 유효성 검사를 추가하면 렌더링 방법이 확실하지 않습니다. 여기 내 댓글 컨트롤러에있는 내용은 다음과 같습니다 (HAML 사용)의 의견과 양식다형성 설명, 주석 유효성 검사가 실패 할 때 렌더링하는 방법?

before_filter :load_resources, :only => [:create] 
def create 
    if @comment.save 
    redirect_to @back 
    else 
    render @action 
    end 
end 

private 

def load_resources 
    @comment = Comment.new(params[:comment]) 
    case @comment.commentable_type 
    when 'A' 
    @a = A.find(params[:a_id] 
    @comments = @a.comments 
    @back = a_url(@comment.commentable_id) 
    @resource = @a 
    @action = 'as/show' 
    when 'B' 
    ... 
    end 
end 

보기 부분 : 내가 알아낼 수있는 것

=render :partial => 'comments/comment', :collection => @comments 

%h3 Leave a comment: 
-form_for [@resource, Comment.new] do |f| 
    =f.error_messages 
    =f.hidden_field :commentable_type, :value => params[:controller].singularize.titleize 
    =f.hidden_field :commentable_id, :value => params[:id] 
    =f.hidden_field :editor_id, :value => @current_user.id 
    =f.hidden_field :creator_id, :value => @current_user.id 
%fieldset 
    =f.label :subject, 'Subject', :class => 'block' 
    =f.text_field :subject, :class => 'block' 
    =f.label :text, 'Comment', :class => 'block' 
    =f.text_area :text, :class => 'block' 
    .clear_thick 
=f.submit 'Submit', :id => 'submit' 

는 유효성 검사 오류를 처리하는 방법입니다. 검증 에러가 발생하면 f.error_messages를 트리거하지 않는 것처럼 보입니다. 게다가 render가 실행될 때 사용자는 a/2/comments를 렌더링 할 때 다음 URL을 가진 페이지로 이동합니다.

최신 해결 방법 : 컨트롤러의 show 액션에서 다음

def create 
    subject = "" 
    if [email protected] 
    subject = "?subject=#{@comment.subject}" 
    end 
    redirect_to @back + subject 
end 

: 그것은 종류의 어려운 포장의

답변

3

if params.has_key?('subject') 
    @comment = Comment.create(:subject => params[:subject]) 
else 
    @comment = Comment.new 
end 

이 작동하지만 종류의 추한 느낌 ... 코멘트 컨트롤러에서 어떤 종류의 객체를 받을지 모르기 때문에 주위를 둘러보십시오.

다형성 관계가 아닌 경우 훨씬 간단합니다. 이를 수행하는 방법을 이해하기 전에 단수 버전을 수행하는 가장 좋은 방법을 이해해야합니다.

나는 이것이 당신이 당신의 자원/경로가 제대로 정의되어 있다고 가정 점에 유의해야합니다

map.resources : 게시물 : has_many => [: 댓글] map.resources : 페이지 : has_many => [ : comments]

포스트의 간단한 예가 많이 있다고 가정 해 보겠습니다. 다음은이 일의 샘플 방법 :

class CommentsController < ApplicationController 
    before_filter => :fetch_post 

    def create 
    @comment = @post.comments.new(params[:comment]) 

    if @comment.save 
     success_message_here 
     redirect post_path(@post) 
    else 
     error_message_here 
     redirect_to post_path(@post) 
    end 
    end 

    protected 
    def fetch_post 
     @post = Post.find(params[:post_id]) 
    end 
end 

이제 우리는 다형성의 관계에서 이것을 사용하려면, 그래서 우리는 설정에 몇 가지가 있습니다. 이제 의견이있는 페이지와 게시물이 있다고 가정 해 보겠습니다. 다음은이 일의 샘플 방법 : 당신이 게시물에서

은 및 페이지 페이지 보여 게시물 컨트롤러에서

<%= render 'comments/new' %> 

:

before_filter :fetch_post 

    def show 
     @comment = @commentable.comments.build 
    end 

    protected 
     def fetch_post 
     @post = @commentable = Post.find(params[:id]) 
     end 

이것은 단순하게 양식을 설정을 : < % error_messsages_for : 의견 %>

<% form_for [ @commentable, @comment ] do |f| %> 
    #Your form fields here (DO NOT include commentable_type and or commentable_id also don't include editor and creator id's here either. They will created in the controller.) 
<% end %> 

r 덧글 컨트롤러 :

def create 
    @commentable = find_commentable 
    # Not sure what the relationship between the base parent and the creator and editor are so I'm going to merge in params in a hacky way 
    @comment = @commentable.comments.build(params[:comment]).merge({:creator => current_user, :editor => current_user}) 

    if @comment.save 
    success message here 
    redirect_to url_for(@commentable) 
    else 
    failure message here 
    render :controller => @commentable.class.downcase.pluralize, :action => :show 
    end 
end 

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

아주 좋은 해결책.호기심에서 직접 작성자와 editor_id를 양식에 포함시키지 않는 이유는 무엇입니까? 그것은 컨트롤러의 복잡성을 줄이는 쉬운 방법이라고 생각합니다. 그 말로는 컨트롤러가 컨트롤러보다 깨끗해야합니까? – LDK

+0

LDK, 일반적으로 사용자 입력을 신뢰해서는 안됩니다. 숨겨진 필드가있는 경우에도 악의있는 ​​사용자는 원하는 ID를 양식에 삽입 한 다음이를 전달하여 다른 사용자로 가장 할 수 있습니다. 해당 옵션을 삭제하면 앱의 보안이 강화됩니다. – Carlos

관련 문제