1

我正在尝试通过创建一个非常简单的应用程序来学习 Rails,该应用程序只是创建一个网站,人们可以在该网站上创建一个作者和书籍列表,并与该书由作者撰写的关联。我希望这会简单而干燥,但我遇到了意想不到的麻烦。

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

应用程序/模型/作者.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 中的值添加了一个选择字段。

app/views/books/_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关联?

4

2 回答 2

0

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

于 2012-10-24T21:58:59.740 回答
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”标签,而不是简单的“author”。

于 2012-10-25T15:17:30.947 回答