几天来一直在努力解决这个问题。我有3个模型书籍,儿童和雇用。我已经为招聘创建了一个视图,允许用户选择2本书和一个孩子,我想要做的是插入两行以将其反映到“雇佣者”中。表。我有一些JS用他们需要的值填充隐藏字段。现在,I don't think nested attributes is the way to go,因为我试图直接插入到连接表中。
所以,我现在尝试的是以下内容:
雇用/ _form.html.erb
<%= form_for(@hire) do |f| %>
<% 2.times do %>
<%= f.hidden_field :child_id %>
<%= f.hidden_field :book_id %>
<% end %>
<%= f.submit 'Take me home' %>
<% end %>
然后我要做的就是贯穿“创造”#39;在我的控制器中运行两次,从而在“雇佣”中创建两行。模型。像这样:
hires_controller.rb
def create
hire_params.each do |hire_params|
@hire = Hire.new(hire_params)
end
end
这完全是错误的方式吗?我正在寻找关于正确方式的建议吗?如果这样可行,那么格式化create语句的最佳方法是什么?
** 修改 **
我有3个型号。每个孩子可以有2本书。这些是我的协会:
class Child < ActiveRecord::Base
has_many :hires
has_many :books, through: :hires
end
class Hire < ActiveRecord::Base
belongs_to :book
belongs_to :child
accepts_nested_attributes_for :book
accepts_nested_attributes_for :child
end
class Book < ActiveRecord::Base
has_many :hires
has_many :children, through: :hires
belongs_to :genres
end
雇用/ new.html.erb
<div class="form-inline">
<div class="form-group">
<h1><label for="genre_genre_id">Pick Book 1:
<%=collection_select(:genre1, :genre_id, @genres.all, :id, :Name, {prompt: true}, {:class => "form-control dropdown"})%></label></h1>
</div>
</div>
<div id="book1-carousel" class="owl-carousel owl-theme">
<% @books.each do |book| %>
<div data-id = "<%= book.id %>" class="tapbook1 tiles <% @genres.each do |g|%> <% if g.id == book.Genre_id %> book1genre<%=g.id %> <% end end%> <%= %>"><a class="item link"><% if book.bookimg.exists? %><%= image_tag book.bookimg.url(:small), :class => "lazyOwl", :data => { :src => book.bookimg.url(:small)}%> <%end%></br><p class="tile_title" ><%= book.Title %></p></a></div>
<% end %>
</div>
<div class="form-inline">
<div class="form-group">
<h1><label for="genre_genre_id">Pick Book 2:
<%=collection_select(:genre2, :genre_id, @genres.all, :Name, :Name, {prompt: true}, {:class => "form-control dropdown"})%></label></h1>
</div>
</div>
<div id="book2-carousel" class="owl-carousel owl-theme">
<% @books.each do |book| %>
<div data-id = "<%= book.id %>" id="<%= book.id %>" class="tapbook2 tiles <% @genres.each do |g|%> <% if g.id == book.Genre_id %> book2genre<%=g.id %> <% end end%> <%= %>"><a class="item link"><% if book.bookimg.exists? %><%= image_tag book.bookimg.url(:small) , :class => "lazyOwl", :data => { :src => book.bookimg.url(:small)}%> <%end%></br> <p class="tile_title"><%= book.Title %></p></a></div>
<% end %>
</div>
<h1 class="child_heading1" >Now choose your name:</h1>
<div id="children-carousel" class="owl-carousel owl-theme">
<% @children.each do |child| %>
<div data-id = "<%= child.id %>" class="tapchild tiles"><a class="item link"><% if child.childimg.exists? %><%= image_tag child.childimg.url(:small), :class => "lazyOwl", :data => { :src => child.childimg.url(:small)} %> <%end%></br> <p class="tile_title"><%= child.nickname %></p></a></div>
<% end %>
</div>
<%= render 'form' %>
和coffeescript:
hires.coffee
$(document).on 'ready page:load', ->
book1carousel = $("#book1-carousel")
book2carousel = $('#book2-carousel')
book1carousel.owlCarousel items: 5, lazyLoad : true
book2carousel .owlCarousel items: 5, lazyLoad : true
$('#children-carousel').owlCarousel items: 5, lazyLoad : true
book1clickcounter = 0
book2clickcounter = 0
childclickcounter = 0
book1selection = 0
book2selection = 0
$('.tapbook1').on 'click', (event) ->
$this = $(this)
book1id = $this.data('id')
book1selection = book1id
if $this.hasClass('bookclicked')
$this.removeAttr('style').removeClass 'bookclicked'
book1clickcounter = 0
$('#hire_book_id').val("");
book1selection = 0
else if book1clickcounter == 1
alert 'Choose one book from this row'
else if book1selection == book2selection
alert "You've already picked this book"
else
$('#hire_book_id').val(book1id);
$this.css('border-color', 'blue').addClass 'bookclicked'
book1clickcounter = 1
return
$('.tapbook2').on 'click', (event) ->
$this = $(this)
book2id = $this.data('id')
book2selection = book2id
if $this.hasClass('book2clicked')
$this.removeAttr('style').removeClass 'book2clicked'
book2clickcounter = 0
book1selection = 0
else if book2clickcounter == 1
alert 'Choose one book from this row'
else if book1selection == book2selection
alert "You've already picked this book"
else
$this.css('border-color', 'blue').addClass 'book2clicked'
book2clickcounter = 1
return
$('.tapchild').on 'click', (event) ->
$this = $(this)
childid = $this.data('id')
if $this.hasClass('childclicked')
$this.removeAttr('style').removeClass 'childclicked'
childclickcounter = 0
$('#hire_child_id').val("");
else if childclickcounter == 1
alert 'Choose one child from this row'
else
$this.css('border-color', 'blue').addClass 'childclicked'
childclickcounter = 1
$('#hire_child_id').val(childid);
return
jQuery ($) ->
$('td[data-link]').click ->
window.location = @dataset.link
return
return
return
答案 0 :(得分:0)
我对此的处理方式是什么称为表单对象,一个类似于模型的类,但只存在于处理多个对象的创建。它提供了精细控制,但代价是重复验证。在我看来(以及许多其他人),在大多数情况下,它比嵌套属性更好。
这是一个例子。请注意,我不知道您的应用程序的功能,并且我没有仔细查看您的关联,以便在此示例中使其准确无误。希望你能得到一般的想法:
class HireWithBookAndChild
include ActiveModel::Model
attr_accessor :child_1_id, :child_2_id, :book_id
validates :child_1_id, presence: true
validates :child_2_id, presence: true
validates :book_id, presence: true
def save
if valid?
@hire = Hire.new(hire_params)
@child_1 = @hire.child.create(id: params[:child_1_id])
@child_2 = @hire.child.create(id: params[:child_2_id])
@book = @hire.book.create(id: params[:book_id])
end
end
end
通过包含AR :: Model,您可以获得验证和可以创建表单的对象。您甚至可以进入i18n文件并为此对象配置验证错误消息。与ActiveRecord模型一样,save方法会自动包装在事务中,因此如果其中一个对象无法持久存在,您将无法获得孤立对象。
您的控制器将如下所示:
class HireWithBookAndChildController < ApplicationController
def new
@hire = HireWithBookAndChild.new
end
def create
@hire = HireWithBookAndChild.new(form_params)
if @hire.save
flash['success'] = "Yay"
redirect_to somewhere
else
render 'new'
end
end
private
def form_params
params.require(:hire_with_book_and_child).permit(:child_1_id, :child_2_id, :book_id)
end
端
您的表单将如下所示:
form_for @hire do |f|
f.hidden_field :child_1_id
...
f.submit
end
你会立即注意到一切都是平的,你不必乱用于field_for和嵌套的嵌套参数,如下所示:
params[:child][:id]
您会发现表单对象使您的代码更容易理解。如果您有需要创建的子项,书籍和雇员的不同组合,只需为每个组合创建一个自定义表单对象。
在这种情况下可能更简单的解决方案是提取服务对象:
class TwoHiresWithChildAndBook < Struct.new(:hire_params)
def generate
2.times do
Hire.create!(hire_params)
end
end
end
从您的控制器:
class HiresController
def create
generator = HireWitHChildAndBook.new(hire_params)
if generator.generate
*some behavior*
else
render :new
end
end
end
这包含了如何在一个地方创建雇佣的知识。我的回答中有更详细的内容:Rails 4 Create Associated Object on Save