Rails 4 RC1多态关联无法创建

时间:2013-05-14 19:53:03

标签: ruby-on-rails ruby-on-rails-4

第三次更新:好的,我认为现在我非常接近。我现在正在创建数据,并且正在DB中设置参数。我改变了业务控制器强大的参数:

def business_params
      params.require(:business).permit(:name, :description, :address_attributes=>[:line1, :line2, :city, :state, :zip])

当我编辑现有业务时,我会因某种原因而创建两个地址。一个是空的,一个是完整的参数。所以,如果有人有最后的推动,我认为我非常接近:)。

地址模型

class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end

商业模式:

    class Business < ActiveRecord::Base

     #each business belongs to user, through user_id
      belongs_to :owner
      has_one :address, as: :addressable
      accepts_nested_attributes_for :address

      # each business has many customers and has many services
      has_many :customers
      has_many :services

    validates :owner_id, presence:true
    validates_presence_of :name
    #validates_length_of :state, is: 2

end

业务总监:

class BusinessesController < ApplicationController
  before_action :get_owner
  before_action :set_business, only: [:show, :edit, :update, :destroy]
  #helper_method :sort_column, :sort_direction


  def index
    @businesses = @owner.businesses
  end

  def show
    #@customer = @business.customers.order(sort_column + " " + sort_direction)
  end

  def new
    @owner = Owner.find(params[:owner_id])
    @business = @owner.businesses.build
    @address = @business.build_address(params[:address])

  end

  def edit
    @address = @business.build_address(params[:address])
  end

  def create
    @business = @owner.businesses.new(business_params)
    @address = @business.create_address(params[:address])

    respond_to do |format|
      if @business.save
        format.html { redirect_to owner_businesses_url(@owner), notice: 'Business was successfully created.' }
        format.json { render action: 'show', status: :created, location: @business }
      else
        format.html { render action: 'new' }
        format.json { render json: @business.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    @address = @business.create_address(params[:address])
    respond_to do |format|
      if @business.update(business_params)
        format.html { redirect_to owner_businesses_url(@owner), notice: 'Business was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @business.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @business.destroy
    respond_to do |format|
      format.html { redirect_to owner_businesses_url(@owner) }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_business
      @business = @owner.businesses.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def business_params
      params.require(:business).permit(:name, :description, :address_attributes=>[:line1, :line2, :city, :state, :zip])
    end

    def get_owner
      @owner = Owner.find(params[:owner_id])
    end

    #def sort_column
    #  Customer.column_names.include?(params[:sort]) ? params[:sort] : "first_name"    
    #end

    #def sort_direction
    #  %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
    #end
  end

表单视图:

        <%= form_for([@owner, @business]) do |f| %>
      <% if @business.errors.any? %>
        <div id="error_explanation">
          <h2><%= pluralize(@business.errors.count, "error") %> prohibited this business from being saved:</h2>

      <ul>
      <% @business.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :description %><br />
    <%= f.text_area :description %>
  </div>

  <%= f.fields_for :address do |address| %>
  <%= p address.object %>
  <div class="field">
    <%= address.label :line1 %><br>
    <%= address.text_field :line1 %>
  </div>
  <div class="field">
    <%= address.label :line2 %><br>
    <%= address.text_field :line2 %>
  </div>
  <div class="field">
    <%= address.label :city %><br>
    <%= address.text_field :city %>
  </div>
  <div class="field">
    <%= address.label :state %><br>
    <%= address.text_field :state %>
  </div>
  <div class="field">
    <%= address.label :zip %><br>
    <%= address.number_field :zip %>
  </div>

  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

现在我创建了两个地址。一个空,一个参数设置。几乎在那里:)。

2 个答案:

答案 0 :(得分:4)

有些东西告诉我,我很大程度上是一个白痴因为难以在我正在研究的Rails 4.0 RC1应用程序中使用多态关联。作为一个白痴,我请求Stack Overflow帮助解决我遇到的问题,然后转发Ruby on Rails&#39;谷歌集团。没有答案,所以,这个问题成为我自己有效解决的第一个问题。

那很好,对吧?

无论如何,我的问题很简单。我希望街道/邮寄/账单地址能够在企业,客户,所有者等之间共享。我不想对三个不同的表进行编码。多态关联似乎是我从这些关联中收集的方式。我四处寻找有关这方面的指导,并确实有一些事情需要建模。

http://kconrails.com/2010/10/19/common-addresses-using-polymorphism-and-nested-attributes-in-rails/>这个网站很有用,虽然过时了。我正在使用Rails 4.我相信这是写在Rails 2的尾端。它确实帮助我缩短了时间,因为我以前从未完成过has_one关联,而我最初的问题出现在Rails控制台中,我无法做到:

b = Owner.first.businesses.first
b.address.create!(params n' stuff)

我一直在创建no_method错误。那时我真的专注于上面的文章,并意识到他也没有使用创造。他正在使用:

b = Owner.first.businesses.first
b.build_address(params n' stuff) -- he actually wrote @customer.build_address

build_association是一个has_one的东西。我现在非常了解这一点。当然,我本可以提前阅读文档,但是,我在此期间阅读了这些文档。如果您有兴趣,可以在http://guides.rubyonrails.org/association_basics.html#has_one-association-reference有效地阅读此内容。

我非常密切地关注该文件,但这并不完全正确。 &#34; build_address&#34;我的业务控制器DID的新方法中的项目允许我的表单中的fields_for显示。但是,没有任何内容写入数据库。正在为所有nil值的地址输入一个空记录,并且根本没有附加到它添加的业务。而且,显然,如果一个企业真的被编辑了#34;而不是创建新的,你根本看不到地址表,所以我想我们至少需要编辑字段中的build_address方法。

我是正确的,但是,仍然没有保存。

我一如既往地去Railscasts看看Ryan有什么。并且,http:// http://ilsilscasts.com/episodes/154-polymorphic-association-revised>他有一些多态的东西,当我为不同的模型添加评论时会很棒。但它并不直接有益于我想在这里做的事情。我在Stack Overflow上阅读了很多内容。检查Github上Rails存储库中的问题列表。阅读Rails Google小组。没有什么能说明我所看到的。

很大程度上是因为我看到了Rails 4问题。

Rails 4中内置了强参数。因此,我将以下内容添加到地址控制器中以解释此问题:

# Never trust parameters from the scary internet, only allow the white list through.
def address_params
  params.require(:address).permit(:line1, :line2, :city, :state, :zip)
end

如果你使用rails g scaffold,这就是脚手架在Rails 4中自然会为你做的。强参数从先前版本的Rails中替换模型中的attr_accessible。因此,该模型只是对地址和可寻址的多态关联的引用,并且业务添加了has_one:地址,如:addressable以及accepts_nested_attributes_for:地址。这一切都很好,但仍然没有任何东西得救。我甚至将address_params哈希添加到appliction_controller.rb。

我意识到我现在是愚蠢的。地址的添加发生在业务控制器中,永远不会看到这个参数哈希。即使在application_controller.rb中也没有任何改变。所以它不可能。

我看到params在日志中传递,并且尝试插入,但是未经许可的params引用&#34;地址&#34;不断展示。

此时我正在寻求帮助并试图调整它。

我看到https://github.com/rails/strong_parameters#nested-parameters>本节在github的强参数库中。我不明白为什么accepts_nested_attributes_for不会为我做这件事,但是我进入了Business控制器并调整那里的params哈希看起来像这样:

# Never trust parameters from the scary internet, only allow the white list through.
def business_params
  params.require(:business).permit(:name, :description, :address_attributes => [:line1, :line2, :city, :state, :zip])
end

我读到的一篇文章说has_one关联传递了一个:address_attributes,所以我把它放在那里。现在情况有所不同。数据仍未保存,但我没有获得任何未经许可的错误。在帮助网站上仍然没有答案。

我决定调整我的新方法,编辑,创建和更新方法。

在新的和编辑中我有:

@business.build_address

我在new中编辑并编辑并添加以创建和更新以下内容:

@business.build_address(params[:address]) -- NOTE, :address_attributes also appears to work there.

现在数据正在保存。所有字段都进入了数据库。问题是两个人。一个是空的,每个新的和每次更新都有一个完成。因此,我从业务控制器中的create和update方法中删除了上面的代码。现在我创建了一个地址。正确。对自己感觉很好,我打开公司编辑地址,我得到一个空白的地址表。没有任何东西被传递回窗体视图。

因此,我将业务控制器中的编辑方法更改为:

@ business.address || = @ business.build_address(params [:address])

这基本上说如果有@ business.address,请显示它,否则将构建@ business.address。

现在我正在滚动。我现在在编辑表单时看到保存的地址。我编辑地址。编辑将保存并再次显示。但与此相关的OLD地址仍然存在。简单地将addressable_id更改为nil并写入新的地址记录。那不是我想要的。仍然没有来自帮助网站的帮助。日志中没有任何东西。

我认为应该在这里使用更新方法。所以我将以下行添加到业务控制器的更新方法中:

@ business.address.update(PARAMS [:地址])

没有行为改变,但现在日志现在显示一个新的未经许可的参数。

它显示&#34; ID&#34;作为不允许的。所以,我将业务控制器params hash更改为:

# Never trust parameters from the scary internet, only allow the white list through.
def address_params
  params.require(:address).permit(:id, :line1, :line2, :city, :state, :zip)
end

就此而言,事情有效。我可以用地址创建一个企业。实际上,即使我没有为地址填写任何内容,也会创建地址(此时不进行验证)。我可以更新该地址,完成或清空,并更新现有记录。有用。我不确定这是最好还是最干净的方式,但我一直在寻找。

如果我手动删除与业务关联的已创建地址并且然后尝试编辑该业务,则存在一个问题,我上面添加的更新方法会抛出错误,因为没有要更新的记录。我可能没有那个生活。我认为我可以创建每个业务(最终用户,所有者,客户等)的记录,即使它是空的,然后只允许通过关联而不是直接删除。

但我可能会调整代码以找到一种方法来创建一个完整的地址而不是将其写为空。

无论如何,目前有些工作。

我很想知道是否有任何我可以改进或应该改变的事情。

现在,我转向下一步。

答案 1 :(得分:1)

在你的控制器中你需要建立模型之间的关系,而不是:

 @business = @owner.businesses.new(business_params)

尝试

 @business = @owner.businesses.build(business_params)