2012-10-24 2 views
1

나는 누군가가 저자와 책의 목록을 작성할 수있는 웹 사이트를 만드는 아주 간단한 응용 프로그램을 작성하여 Rails를 배우려고합니다. 나는 이것이 단순하고 건조한 상태가되기를 바랐지만, 예상치 못한 문제가있었습니다.적절한 Association in Rail을 선택하는 방법은 무엇입니까?

내 모델을 처음 보았을 때 연관성을 설정하고 모든 데이터 요소를 필요로했습니다 (author.name, book.title 및 book.author). 적절한 레일 규칙을 사용하기 때문에 author 또는 author_id를 attr_accessible 목록에 추가하고 싶지 않습니다.

응용 프로그램/모델/author.rb :

class Author < ActiveRecord::Base 
    attr_accessible :name 
    validates_presence_of :name 
    has_many :books 
end 

응용 프로그램/모델/book.rb :

class Book < ActiveRecord::Base 
    attr_accessible :title 
    validates_presence_of :title 
    belongs_to :author 
    validates_associated :author 
end 

내가 생각하는 책의 컨트롤러와 뷰는 비계 매우 재미에서 정확하게이다. 흥미로운 것은 책 컨트롤러입니다. 새로운 메소드를 살펴보면 ID에 작성자 이름의 배열을 가져 와서 뷰로 전달하는 콜렉터를 추가하는 것이 었습니다. (솔직히, 나는 전혀 ID를 통과하지하는 것을 선호 생각합니다.)

응용 프로그램/컨트롤러/books_controller.rb

# GET /books/new 
    # GET /books/new.json 
    def new 
    @book = Book.new 
    @authors = Author.all.collect {|a| [a.name, a.id]} 

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

을 지금 이상보기에, 나는 기본 new.html.haml을 사용 _form.html.haml을 변경했습니다. @authors의 값을 사용하여 선택 필드를 추가했습니다.

응용 프로그램 /보기/책/_form.html.haml

= form_for @book do |f| 
    - if @book.errors.any? 
    #error_explanation 
     %h2= "#{pluralize(@book.errors.count, "error")} prohibited this book from being saved:" 
     %ul 
     - @book.errors.full_messages.each do |msg| 
      %li= msg 

    .field 
    = f.label :name 
    = f.text_field :name 
    .field 
    = f.label :author 
    = f.select(:author, @authors, {:include_blank => ""}) 
.actions 
    = f.submit 'Save' 

마지막에게, 나의 컨트롤러로 만드는 방법. 기본 매개 변수를 저장하고 선택한 작성자와 작성자 연결을 만들려고합니다.

응용 프로그램/컨트롤러/books_controller.rb

# POST /books 
    # POST /books.json 
    def create 
    @book = Book.new(params[:book]) 
    @book.author = Author.find_by_id(params[:author]) 

    respond_to do |format| 
     if @book.save 
     format.html { redirect_to @book, notice: 'Book was successfully created.' } 
     format.json { render json: @book, status: :created, location: @book } 
     else 
     format.html { render action: "new" } 
     format.json { render json: @book.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

나는 다음과 같은 오류 얻을 '저장'을 클릭하면 : 내가 선택한 값에 넣어 때문에이 것을 이해

Can't mass-assign protected attributes: author 

을 params [: author] 대신 params [: book]을 사용하십시오. 그래서 두 가지 질문이 있습니다.

1) select 문을 params [: book] 대신 params [: author]로 보내려면 어떻게 수정해야합니까?

2) ID 연결을 완전히 숨기는 더 좋은 방법이 있습니까?

답변

0

나는 대부분 그것을 알아 냈어요, 나는 의심으로, I didn를 생각한다 내 모델 코드를 전혀 변경하지 않아도됩니다.

나는 만 반환 저자 이름에 @authors 내 컨트롤러 새로운 방법 정의를 변경 한 다음

@authors = Author.pluck(:name) 

내가으로 검색해야하는 경우는 아마 조금 느린 비록이 ID를 숨기는 내 목표를 달성 id 대신 controller create 메소드를 사용하십시오 (아래).

다음으로 params [: book] [: author] 대신 params [: author]를 설정하도록 내보기가 수정되었습니다.

@book = Author.find_by_name(params[:author]).books.create(params[:book]) 

나는 이것에 매우 행복 해요 :

= label :author, :name, 'Author' 
= select_tag(:author, options_for_select(@authors), {:include_blank => ""}) 

마지막으로, 나는 @book의 새로운 방법 생성을 변경했습니다. 내가 정말로 좋아하지 않는 유일한 점은 레이블이 단순히 "저자"가 아닌 "저자명"레이블을 생성한다는 것입니다.

+0

죄송합니다. label_tag : author를 사용할 수 있습니다. – Geoff

+0

컨트롤러가 @book = Book.new (params [: book]) 및'@book.author = Author.find_by_name (params [: author])'로 변경되었습니다. 이것은 읽기가 쉽고 대량 속성 경고를 발생시키지 않으며 오류로 다시 렌더링해야하는 경우 오류가 표시 될 수있는'@ 책 '이 있음을 보장합니다. – Geoff

0

"대량 할당 보호 할 수 없습니다 속성 : 저자는"당신의 속성이 모델에 attr_accessible로 나열되지 않음을 의미합니다

+0

예, 의도적 인 내용입니다. 내 질문의 핵심은 모델을 변경하지 않고이 "작업"을 어떻게 만듭니 까? – Geoff

관련 문제