Как мне создать представление для ассоциации has_one? - PullRequest
5 голосов
/ 07 апреля 2011

Итак, представьте, у меня есть эта модель:

class Car
  has_one :engine
end

и модель двигателя:

class Engine
  belongs_to :car
end

Когда я представляю форму для пользователя, чтобы он мог создать новую машину, я хочу разрешить ему выбирать только один из доступных двигателей (доступные двигатели будут в select, заполненном collection_select). Дело в том, что если я построю поле так:

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

Когда я попытаюсь сохранить его, я получу сообщение AssociationTypeMismatch, в котором говорится, что он ожидал Engine, но получил строку.

Это способ сделать это?

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_one и belongs_to единственным способом достижения этого?

Я потерян, и мне кажется, что мне здесь не хватает чего-то очень простого.

Ответы [ 3 ]

8 голосов
/ 07 апреля 2011

Вы должны использовать engine_id

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

UPD

, поскольку Engine не принадлежит_ к Car, поэтому вы должны использовать здесь вложенные атрибуты.Этот скринкаст будет очень полезен для вас:

Оформить заказ 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 %>
0 голосов
/ 18 июля 2016

Я столкнулся с той же проблемой, и вот мое решение (улучшения, основанные на ответе fl00r ):

  1. Сделайте все как fl00r сказал.

  2. Добавьте optional: true к описанию класса

Класс Двигатель принадлежит_в машине: необязательный: истина конец

Дополнительная информация по адресу: 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 %>

Дополнительная информация по адресу: Остановить рельсы для создания скрытого поля для fields_for метода

Модифицируйте свой EngineController

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.Добавить функцию (приватную)

def set_engine

  engine_id = car_params[:engine_attributes][:id]

  @engine = Engine.find(engine_id)

  @car.engine = @engine

  @car.save
end

3.2.Измените EngineController # update

  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
0 голосов
/ 09 сентября 2013

Ответ на предыдущий ответ от Кайла - мне нравится этот простой подход, однако мне пришлось изменить его следующим образом, чтобы работать для моего приложения (я в Rails 3.2.13).Суть в том, что карта должна возвращать массив - так что, я думаю, это была опечатка, в которой два массива были разделены запятой.Я также изменил строковую ссылку на атрибут id на символ, но я не уверен, является ли это необходимым или просто другим вариантом.По крайней мере, вот что сработало для меня.

<%= f.select :class_location_id, ClassLocation.all.map {|e| [e.place, e.id]} %>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...