如何在Rails中选择合适的Association?

时间:2012-10-24 21:41:15

标签: ruby ruby-on-rails-3 activerecord associations

我正在尝试通过创建一个非常简单的应用程序来学习Rails,该应用程序只创建一个网站,其中某人可以创建一个作者和书籍列表,其中一个关联书是由作者编写的。我希望这很简单干,但我一直遇到意想不到的麻烦。

首先查看我的模型,我已经设置了关联并且需要每个数据点(author.name,book.title和book.author)。我不想将:author或:author_id添加到attr_accessible列表中,因为我想使用适当的Rails约定。

应用程序/模型/ 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'

最后,返回我的控制器以获取create方法。我尝试保存基本参数并从所选作者创建作者关联。

应用程序/控制器/ 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 [:book]而不是params [:author]中。所以我有两个问题。

1)如何修复我的select语句,让它以params [:author]而不是params [:book]发送?

2)是否有更好的方法可以完全隐藏id关联?

2 个答案:

答案 0 :(得分:0)

“无法批量分配受保护的属性:作者”表示您的属性未在模型中列为attr_accessible

答案 1 :(得分:0)

我想我已经把它弄清楚了,而且我怀疑,我根本不需要改变我的模型代码。

我将@authors的控制器新方法定义更改为仅返回作者姓名:

@authors = Author.pluck(:name)

这实现了我隐藏id的目标,虽然当我需要在控制器创建方法(下面)中按名称而不是id进行搜索时,它可能会慢一点。

接下来,我修改了我的观点来设置params [:author]而不是params [:book] [:author]。

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

最后,我更改了@book的新方法创建:

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

我对此非常满意。我唯一不喜欢的是标签创建了一个“author_name”标签,而不仅仅是“作者”。