如何为has_one关联创建视图



假设我有这样一个模型:

class Car
  has_one :engine
end

和引擎模型:

class Engine
  belongs_to :car
end

当我为用户呈现表单以便他可以创建一辆新车时,我只希望允许他从一个可用的引擎中进行选择(可用的引擎将在select中,由collection_select填充)。问题是,如果我像这样创建字段:

<%= f.collection_select :engine,Engine.all,:id,:name %>

当我尝试保存它时,我将得到一个AssociationTypeMismatch,它说它期望一个引擎,但它收到一个字符串。

是这样做的吗?

def create
  car = Car.new(params[:car])
  engine = Engine.find(params[:engine])
  car.engine = engine
  if car.save
     # redirect somewhere
  else
     # do something with the errors
  end
end

我一直觉得Rails可以自动完成一些事情,比如将引擎和汽车关联起来,但是我不知道如何让他做到这一点。

切换has_onebelongs_to关联是实现这一目标的唯一方法吗?

我迷路了,我觉得我错过了一些非常基本的东西。

您应该使用engine_id

<%= f.collection_select :engine_id, Engine.all, :id, :name %>

乌利希期刊指南

,因为Engine不是belongs_to Car,所以你应该在这里使用嵌套属性。这个视频对你很有用:

  • http://railscasts.com/episodes/196-nested-model-form-part-1
  • http://railscasts.com/episodes/197-nested-model-form-part-2

Checkout api: http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for

简短的介绍:

class Car
  has_one :engine
  accepts_nested_attributes_for :engine
end

和在你的表单中:

<%= form_for @car ... do |f| %>
  ...
  <%= f.fields_for :engine do |b| %>
    <%= b.collection_select :id, Engine.all, :id, :name %>
    ...
  <% end %>
  ...
<% end %>

我遇到了同样的问题,这是我的解决方案(基于fl00r答案的改进):

  1. 按照fl00r所说的去做

  2. optional: true添加到类描述中

class Engine belongs_to:car, optional: true end

更多信息请访问:http://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html

  • 修改
  • <%= f.fields_for :engine do |b| %>
      <%= b.collection_select :id, Engine.all, :id, :name %>
      ... 
    <% end %>
    

    <%= f.fields_for :engine, :include_id => false do |b| %>
      <%= b.collection_select :id, Engine.all, :id, :name %>
      ...
    <% end %>
    

    更多信息请参见:Stop rails from为fields_for方法生成隐藏字段

  • 修改引擎控制器
  • 3.1。修改

    def car_params
      params.require(:car).permit(:name)
    end
    

    def car_params
      params.require(:car).permit(:name, engine_attributes: [:id, :name])
    end
    

    更多信息见:Rails 4嵌套属性不允许的参数

    3.1。添加一个函数(private)

    def set_engine
      engine_id = car_params[:engine_attributes][:id]
      @engine = Engine.find(engine_id)
      @car.engine = @engine
      @car.save
    end
    

    3.2。修改EngineController #更新

      def update
        respond_to do |format|
          if @car.update(car_params)
            format.html { redirect_to @car, notice: 'Car was successfully updated.' }
            format.json { render :show, status: :ok, location: @car }
          else
            format.html { render :edit }
            format.json { render json: @car.errors, status: :unprocessable_entity }
          end
        end
      end
    

      def update
        respond_to do |format|
          if set_engine && @car.update(car_params)
            format.html { redirect_to @car, notice: 'Car was successfully updated.' }
            format.json { render :show, status: :ok, location: @car }
          else
            format.html { render :edit }
            format.json { render json: @car.errors, status: :unprocessable_entity }
          end
        end
      end
    

    回复Kyle之前的回答——我喜欢这种简单的方法,但是我不得不按照以下方式更改它来为我的应用程序工作(我在Rails 3.2.13中)。重点是映射需要返回一个Array——所以我认为这可能是一个错别字,用逗号分隔了两个数组。我还将id属性的字符串引用更改为符号,但我不确定这是必要的还是只是另一种选择。至少,以下是对我有用的方法。

    <%= f.select :class_location_id, ClassLocation.all.map {|e| [e.place, e.id]} %>
    

    相关内容

    • 没有找到相关文章

    最新更新