2

第三次更新:好的,我想现在我很接近了。我现在正在创建数据,并且正在数据库中设置参数。我将业务控制器强参数更改为:

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 %>

现在我正在创建两个地址。一个是空的,一个是带参数的。差不多好了 :)。

4

2 回答 2

4

有些事情告诉我,我主要是个白痴,因为我很难让多态关联在我正在开发的 Rails 4.0 RC1 应用程序中工作。作为一个白痴,我确实要求 Stack Overflow 帮助解决我看到的问题,并转发了 Ruby on Rails 的 Google Group 的问题。没有答案,因此,这个问题成为我自己有效解决的第一个问题。

所以这很好,对吧?

无论如何,我的问题很简单。我希望在企业、客户、所有者等之间共享街道/邮寄/帐单地址。我不想编写三个不同的表来做同样的事情。多态关联似乎是我从此类关联中收集到的方法。我四处寻找这方面的指导,并且确实有一些东西可以模仿。

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 错误。那是我真正专注于上面的文章并意识到他也没有使用 create 的时候。他正在使用:

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上有效地阅读此内容。

我非常密切地关注该文件,但它并不完全正确。我的业务控制器 DID 的新方法中的“build_address”项允许显示我的表单中的 fields_for。但是,没有任何东西被写入数据库。正在为所有 nil 值的地址输入一条空记录,并且根本没有附加到为其添加它的业务。而且,显然,如果要实际“编辑”业务而不是创建新业务,您将根本看不到地址表单,所以我认为我们至少需要在编辑字段中使用 build_address 方法。

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

和往常一样,我去 Railscasts 看看 Ryan 有什么。而且,http://http://railscasts.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 :address,as:addressable 以及accepts_nested_attributes_for :address。这一切都很好,但仍然没有任何东西被保存。我什至将 address_params 哈希添加到 appliction_controller.rb 中。

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

我看到参数正在日志中传递,并尝试插入,但对“地址”的未经许可的参数引用不断显示。

我在这一点上寻求帮助并试图调整它。

我在强参数存储库的 github 上看到 https://github.com/rails/strong_parameters#nested-parameters> 这个部分。我不明白为什么 Accepts_nested_attributes_for 不会为我这样做,但我进入业务控制器并在那里调整 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 和 edit 中更改了它并添加了以创建和更新以下内容:

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

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

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

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

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

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

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

@business.address.update(params[:address])

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

它将“ID”显示为未经许可。因此,我将业务控制器参数哈希更改为:

# 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

在这方面,事情奏效了。我可以创建一个有地址的企业。事实上,即使我没有为地址填写任何内容,也会创建地址(此时没有验证)。我可以更新该地址,无论是完整的还是空的,它都会更新现有记录。有用。我不确定这是最好或最干净的方法,但我会继续寻找。

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

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

无论如何,目前情况还不错。

我很想知道是否有什么可以改进或应该改变的。

现在,我转到下一件事。

于 2013-05-17T17:48:45.657 回答
1

在您的控制器中,您需要建立模型之间的关系,所以不要:

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

尝试

 @business = @owner.businesses.build(business_params)
于 2013-05-14T21:34:49.370 回答