【问题标题】:How do I delete records saved with collection_select in Rails?如何在 Rails 中删除使用 collection_select 保存的记录?
【发布时间】:2013-09-27 01:24:11
【问题描述】:

我的目标是能够在从 collection_select 中取消选择项目时更新保存的记录(然后重新提交该记录。)提前感谢您的帮助!

详情

我有一个 Newsavedmaps 的表格。 Newsavedmaps 可以有许多航路点。用户可以在 collection_select 中选择航点,当他们保存 Newsavedmap 时,这些航点会保存到自己的数据库表中。

问题:当用户打开他们保存的 Newsavedmap 时,我希望他们能够取消选择航点。当他们再次保存 Newsavedmap 时,我希望删除取消选择的航点。

这是我正在维护的 Rails 2.3X 应用程序,这就是为什么 collection_select 在下面使用不同格式的原因。

型号

class Newsavedmap < ActiveRecord::Base
  belongs_to :itinerary
  has_many :waypoints, :dependent => :destroy
  accepts_nested_attributes_for :waypoints, :reject_if => lambda { |a| a[:waypointaddress].blank? }, :allow_destroy => true
end

查看

    <% form_for @newsavedmap, :html => { :id => 'createaMap' } do |f| %>
      <%= f.error_messages %>               
      <%= f.text_field :name, {:id=>"savemap_name", :size=>30 }%></p>

      <%= collection_select :waypoints, :waypointaddress, @newsavedmap.waypoints, :waypointaddress, :waypointaddress, {}, { :multiple => true, :class => "mobile-waypoints-remove", :id =>"waypoints" } %>

    <% end %> 

Newsavedmaps 控制器

def create
  @newsavedmap = Newsavedmap.new(params[:newsavedmap])
  waypoint = @newsavedmap.waypoints.build

  respond_to do |format|
    if @newsavedmap.save
      flash[:notice] = 'The new map was successfully created.'
      format.html { redirect_to "MYURL"}
      format.xml  { render :xml => @newsavedmap, :status => :created, :location => @newsavedmap }
    else
      format.html { render :action => "new" }
      format.xml  { render :xml => @newsavedmap.errors, :status => :unprocessable_entity }
    end
  end
end


def update
  @newsavedmap = Newsavedmap.find(params[:id])

  if @newsavedmap.itinerary.user_id == current_user.id
    respond_to do |format|
      if @newsavedmap.update_attributes(params[:newsavedmap])
        flash[:notice] = 'Newsavedmap was successfully updated.'
        format.html { redirect_to "MYURL" }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @newsavedmap.errors, :status => :unprocessable_entity }
      end
    end
  else
    redirect_to '/'
  end
end

创建新记录时的参数

参数:{"newsavedmap"=>{"name"=>"我的地图名称", OTHER FIELDS NOT SHOWN ABOVE, "waypoints"=>{"waypointaddress"=>["1600 Pennsylvania Ave NW, Washington, DC 20500", "350 5th Ave, New York, NY 10118"]}}

【问题讨论】:

  • 您可以发布来自您的表单的参数
  • 已添加。事实证明,上面是在航路点数据库中创建一个新的空记录(而不是两个航路点记录,每个记录都有一个地址。)我认为这是因为我的控制器告诉表单每次有一个新的航路点建立一个新的Newsavedmap,但它完全忽略了数据。有什么想法吗?
  • 关于数据库中的空记录:你是对的。在方法create 中,您从参数初始化一个新的@newsavedmap,然后构建一个新的waypoints 并保存@newsavedmap - 这将保存@newsavedmap 和构建的航点。在方法 create 中为航点移除此建筑物

标签: mysql ruby-on-rails rails-activerecord


【解决方案1】:

我认为您的问题是正确构建的形式(以及来自它的参数)。

我建议

  1. 看宝石cocoonnested_form
  2. waypoints_attributes 添加到 attr_accessible
  3. 在您的表单中实现来自 gem(从第 1 点开始)的助手

Rails 的魔法应该完成其他工作

【讨论】:

  • 感谢您的回复,哥特瓦。不幸的是,我不能依赖宝石。但我确实有一个问题:无论如何我是否有必要包含 attr_accessible ,如果是,它会去哪里?
  • 关于 gems:我认为在没有 gems 的情况下为accept_nested_attributes 正确构建表单会很困难。关于attr_accessible:不,没有必要,但在这种情况下,您应该关心手动分配参数,就像这样@newsavedmap.waypoints_attributes = params[:newsavedmap][:waypoints_attributes]。如果要添加attr_accessible,请将其添加到模型Newsavedmap(请记住,如果未设置attr_accessible,则默认情况下所有属性都在此列表中)
  • 谢谢,哥特瓦!我将跳过 attr_accessible。我阅读了您的评论,但是必须有一种方法可以使用 collection_select 添加和删除记录,而无需使用嵌套表单的 gem,对吗?有什么想法吗?
  • 您应该构建可以构建并传递给具有特殊结构的控制器参数的表单。 There is 类似 period_attributes 的示例。我怀疑collection_select 可以构建这样的参数。也许我错了,Rails 2.3 有一种方法可以为 accept_nested_attributes 构建参数。 PS你能解释一下为什么你不想使用gem(我相信它们的某些版本适用于Rails 2.3)
【解决方案2】:

另一种变体(不使用宝石)(我认为要困难得多!

您可以完全删除 accept_nested_attributes 并直接使用您的参数。但在这种情况下,您应该手动管理所有过程:正确插入记录,正确销毁记录。

在您的情况下,它应该像这样(未经测试!)。该示例基于您在问题中发布的参数。

def create
  # delete params 'waypoints' it will be manage manually
  waypoints = params[:newsavedmap].delete(:waypoints)
  @newsavedmap = Newsavedmap.new(params[:newsavedmap])
  waypoints.each do |waypoint|
    @newsavedmap.waypoints.build(:waypointaddress => waypoint)
  end
  if @newsavedmap.save
    ...
  end
end

主要的麻烦在于方法update

def update
  # delete params 'waypoints' it will be manage manually
  waypoints = params[:newsavedmap].delete(:waypoints)

  # find and setup attributes
  @newsavedmap = Newsavedmap.find(params[:id])
  @newsavedmap.attributes = params[:newsavedmap]

  # TROUBLES start here
  # destroy not checked (but existed in DB) waypoints
  existed_waypoints = @newsavedmap.waypoints
  existed_waypoint_addresses = existed_waypoints.map(&:waypointaddress)
  new_waypoints = []
  waypoints.each do |waypoint|
    if existed_waypoint_addresses.include?(waypoint)
      # existed waypoint was selected on the form
      # find it and add to new_waypoints
      new_waypoints << @newsavedmap.waypoints.find_by_waypointaddress(waypoint)
    else
      # new waypoint was selected on the form
      # build it and add to new_waypoints
      new_waypoints << @newsavedmap.waypoints.build(:waypointaddress => waypoint)
    end
  end
  # setup new records for waypoints
  @newsavedmap.waypoints = new_waypoints

  if @newsavedmap.save
    # destroy existed but not selected waypoints
    (existed_waypoints - new_waypoints).map(&:destroy)
    ...
  end
end

【讨论】:

  • Gotva,我非常感谢这次更新。但是,我想在这里使用嵌套表单,而不是试图绕过它们。一定有一种方法可以使用 collection_select 添加和删除记录,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-01
相关资源
最近更新 更多