我正在尝试通过创建一个非常简单的应用程序来学习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关联?
答案 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”标签,而不仅仅是“作者”。