0

这是我几天前提出的另一个多态问题的后续。我正在为地址创建多态关联。在这种情况下,我只是想看看它是否可以在一个简单的模型中工作,所以我在我制作的现有测试博客中的“文章”中添加了一个“地址”。我的问题是我现在可以使用新的“文章”创建一个地址(知道文章将是真实应用程序中的企业、用户、客户等),并在我去编辑该业务时看到它。但是,如果我编辑地址,现有地址的 addressable_id 将设置为 nil,并创建一个新地址,留下旧地址并更新新地址的 addressable_id。我无法想象这是正确的行为,尽管也许我是以某种方式对自己做的。

这是代码。

文章模型

class Article < ActiveRecord::Base
  has_one :address, as: :addressable
  accepts_nested_attributes_for :address
end

地址模型

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

物品控制器

class ArticlesController < ApplicationController
  before_action :set_article, only: [:show, :edit, :update, :destroy]


  # GET /articles
  # GET /articles.json
  def index
    @articles = Article.all
  end

  # GET /articles/1
  # GET /articles/1.json
  def show
  end

  # GET /articles/new
  def new
    @article = Article.new
    @address = @article.build_address(params[:address])
  end

  # GET /articles/1/edit
  def edit
    @address = @article.address ||= @article.build_address(params[:address])  
  end

  # POST /articles
  # POST /articles.json
  def create
    @article = Article.new(article_params)

    respond_to do |format|
      if @article.save
        format.html { redirect_to @article, notice: 'Article was successfully created.' }
        format.json { render action: 'show', status: :created, location: @article }
      else
        format.html { render action: 'new' }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /articles/1
  # PATCH/PUT /articles/1.json
  def update
    @address = 
    respond_to do |format|
      if @article.update(article_params)
        format.html { redirect_to @article, notice: 'Article was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /articles/1
  # DELETE /articles/1.json
  def destroy
    @article.destroy
    respond_to do |format|
      format.html { redirect_to articles_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_article
      @article = Article.find(params[:id])
    end

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

我的数据库迁移文件

class CreateAddresses < ActiveRecord::Migration
  def change
    create_table :addresses do |t|
      t.string :line1
      t.string :line2
      t.string :city
      t.string :state, limit: 2
      t.integer :zip, limit: 5
      t.references :addressable, polymorphic: true

      t.timestamps
    end
     add_index :addresses, [:addressable_type, :addressable_id], unique: true
  end
end

视图是标准的

<%= f.fields_for :address do |address| %>
  Fields n stuff.....
<% end %>

正如我所提到的,一切似乎都在这个级别上工作。我仍然对我最初的问题有疑问,并认为这与在那里嵌套有关,所以我会解决这个问题。我只是想在添加之前确保我知道这是正确的。

当您编辑与“文章”相关的现有地址时——在这种情况下——它应该离开旧地址并创建一个新地址,还是更新现有地址?我缺少一些简单的东西吗?

4

1 回答 1

0

我大部分时间都在工作。

不确定这是否正确,但它似乎有效。这很长,但是:

有些事情告诉我,我主要是个白痴,因为我很难让多态关联在我正在开发的 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:45:09.577 回答