2016-01-01 2 views
1

Я пытаюсь сделать приложение в Rails 4.Rails 4 - полиморфные ассоциации

У меня есть модель профиля и модель адреса.

в Ассоциации являются:

profile.rb

has_many :addresses, as: :addressable 

address.rb

belongs_to :addressable, :polymorphic => true 

Адрес является полиморфным модель.

У меня есть форма, которая имеет адрес:

<%= simple_form_for(@address) do |f| %> 
      <%= f.error_notification %> 

      <div class="form-inputs"> 
       <div class="row"> 
        <div class="col-xs-3"> 
         <%= f.input :unit %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :street_number %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :street %> 
        </div> 
       </div> 

       <div class="row"> 
        <div class="col-xs-3"> 
         <%= f.input :building %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :city %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :region %> 
        </div> 

       </div> 

       <div class="row"> 
        <div class="col-xs-3"> 
         <%= f.input :zip %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :country, priority: [ "Australia", "New Zealand", "United Kingdom" ] %> 
        </div> 


       </div> 

       <div class="row"> 
        <div class="col-xs-3"> 
         <%= f.input :main_address %> 
        </div> 
        <div class="col-xs-3 col-xs-offset-1"> 
         <%= f.input :project_offsite %> 
        </div> 


       </div> 



      </div> 

      <div class="form-actions"> 
       <%= f.button :submit, :class => "formsubmit" %> 
      </div> 
      <% end %> 

Я пытаюсь создать адрес и сохранить его. Затем я проверяю, что он находится в консоли rails. Что-то происходит не так, потому что консоль рельсы показывает это:

#<Address id: 1, unit: "", building: "", street_number: "34", street: "f", city: "sdfasdf", region: "asdf", zip: "2000", country: "GB", main_address: nil, project_offsite: nil, time_zone: nil, latitude: nil, longitude: nil, addressable_id: nil, addressable_type: nil, created_at: "2015-12-30 00:07:00", updated_at: "2015-12-30 00:17:00"> 

Адресный идентификатор и адресацией тип оба равны нулю.

У них должны быть ссылки на профиль или везде, где есть соответствующая модель.

Есть ли недостаток в настройке этого процесса?

Это видео (минута 3.40) говорит, что рельсы автоматически обрабатывают заполнение полей типа и идентификатора для полиморфных моделей. https://gorails.com/episodes/comments-with-polymorphic-associations?autoplay=1

Когда я пытаюсь создать новый адрес из консоли рельсы, я типа:

Address.create(addressable: Address.first, profile_id: "1", country: "AU") 

Ошибка консоли:

ActiveRecord::UnknownAttributeError: unknown attribute 'profile_id' for Address 

Мой адрес таблица имеет ключ addressable_id и мой модель профиля имеет has_many: адреса, как:: адресуемый

Я не могу понять, что вызывает ошибку

ДРУГАЯ ПОПЫТКА

Таким образом, от того, что я понял из приведенных ниже предложений, мне нужно сделать что-то, чтобы адрес знать, что он принадлежит к профилю.

Я также нашел эту статью, в которой излагается примером того, что должно произойти в контроллере профилей, чтобы все заработало с полиморфными ассоциациями: http://6ftdan.com/allyourdev/2015/02/10/rails-polymorphic-models/

я изменю свое новое действие в контроллере профилей на адрес (адрес ,строить):

def new 
    @profile = Profile.new 
    @profile.qualifications.build 
    @profile.visions.build 
    @profile.personalities.build 
    @profile.addresses.build 

    authorize @profile 
    end 

добавить вложенные атрибуты в мой адрес ассоциации в модели профиля:

has_many :addresses, as: :addressable 
    accepts_nested_attributes_for :addresses, reject_if: :all_blank, allow_destroy: true 

я изменить свой адрес формы: - от form_for до fields_for; - переименовать его _address_fields.html.erb; и - открыть DIV тег:

<div class="nested-fields"> 

В моей профили форме, добавить ссылку на форму парциального:

   Your addresss 
      </div> 
      <%= f.simple_fields_for :addresses do |f| %> 

       <%= render 'addresses/address_fields', f: f %> 
      <% end %> 
      </div> 
      <div class="row"> 
      <div class="col-md-6"> 

       <%= link_to_add_association 'Add an address', f, :addresses, partial: 'addresses/address_fields' %> 

      </div> 

Все это, как указано в ответе Jeiwan на этот пост : Rails - Cocoon gem - Nested Forms

Тогда, когда я пытаюсь все это, я получаю эту ошибку:

ActiveRecord::RecordNotUnique in ProfilesController#update 
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_addresses_on_addressable_type_and_addressable_id" DETAIL: Key (addressable_type, addressable_id)=(0, 1) already exists. : INSERT INTO "addresses" ("unit", "building", "street_number", "street", "city", "region", "zip", "country", "addressable_id", "addressable_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" 

Точки ошибки в методе обновления в контроллере профилей:

def update 
    respond_to do |format| 
     if @profile.update(profile_params) 
     format.html { redirect_to @profile } 
     format.json { render :show, status: :ok, location: @profile } 
     else 

Я нашел этот пост, который описывает подобную проблему пользователя, но, прежде чем я изменить базу данных, я хотел бы, чтобы попытаться понять, что произошло.

Rails auto-assigning id that already exists

Другая странная вещь, когда я смотрю на последний адрес, созданный в консоли, он показывает это:

#<Address id: 6, unit: "", building: "", street_number: "34", street: "asdf", city: "asdf", region: "add", zip: "2111", country: "AU", main_address: nil, project_offsite: nil, time_zone: nil, latitude: nil, longitude: nil, addressable_id: 1, addressable_type: 0, created_at: "2016-01-01 22:01:31", updated_at: "2016-01-01 22:01:31">]> 

Пластинка теперь имеет addressable_id, но не имеет addressable_type. Есть ли что-то, что необходимо для заполнения этого поля?

ответ

1

Эта форма не содержит полей ввода/типа addressable, поэтому, если вы явно не установили их или связанный с ними объект в контроллере, получение nil - это то, что ожидается.

Определение отношения в модели только утверждает, что объекты могут быть связаны таким образом, но не устанавливают фактические значения. На самом деле - рельсы имеет много магии в ней, но она не может угадать, profile является владельцем которого адрес

+0

но как вы их устанавливаете? – Mel

+0

@ user2860931 просто объявляйте их скрытыми или выбирайте для адресации, или если вы просто сможете установить его позже, оставьте как есть, просто пропустите validate addressable_id в нуле. –

+0

, но если адресная форма принадлежит профилю, а путь профиля редактирования ведет к адресной форме, это не ссылка. Если я разрешу пользователям выбирать идентификатор, то он будет выглядеть очень странным в форме, если пользователю будет предложено выбрать свой собственный идентификатор профиля, чтобы добавить адрес. Ни один из примеров не показывает требование для скрытого поля, чтобы это работало. Пожалуйста, вы можете показать мне ссылку на пример этого? Большое спасибо – Mel

0

Вы путаться с polymorphic associations:

With polymorphic associations, a model can belong to more than one other model, on a single association

Это означает, что ActiveRecord будет автоматически присвойте addressable_type & addressableid модели Address, в зависимости от того, какая связанная с ней модель создала его.

Например ...

#app/models/profile.rb 
class Profile < ActiveRecord::Base 
    has_many :addresses, as: :addressable 
end 

#app/models/address.rb 
class Address < ActiveRecord::Base 
    belongs_to :addressable, polymorphic: true 
end 

Вышесказанное означает, что каждый раз, когда вы создаете профиль, у вас есть возможность создать или назначить адреса для него. Если у вас была другая модель (users), вы могли бы сделать то же самое.addressable_id & addressable_type будет назначен автоматически на address записи:

#app/controllers/profiles_controller.rb 
class ProfilesController < ApplicationController 
    def create 
     @profile = Profile.new profile_params 
     @profile.save 
    end 

    private 

    def profile_params 
     params.require(:profile).permit(...) 
    end 
end 

-

Основная проблема у вас есть то, что вы путаясь между которыми модель имеет polymorphic элемент ассоциации.

They should have the references back to profile or wherever the related model is.

@profile = Profile.find x 
@address = @profile.addresses.new address_params ... 

Это присвоит addressable_id и addressable_type для profile модели, что позволяет создавать адреса от имени profile.

@address = current_user.addresses.new address_params 

Это точно такой же код позволит вам создать адрес для пользователя (та же модель, те же ассоциации и т.д.).


Чтобы ответить на ваш вопрос, вы должны рамки вашего создания объекта вокруг соответствующей модели:

@address = Address.create(country: "AU") 

@profile = Profile.find 1 
@profile.addresses << @address 

Вы также можете сделать:

@profile = Profile.find 1 
@profile.addresses.create country: "AU" 

-

Если вы хотите, чтобы адреса были «зависимыми» от других, вам нужно добавить столбец parent_id и использовать acts_as_tree или другой драгоценный камень иерархии.

+0

Я могу обновить это, если неясно –

+0

Привет Rich. Спасибо за это. Я не уверен, что вы предлагаете, как связать адрес с профилем. Нужно ли добавлять что-то к новому профилю контроллера для создания profile.address? Посмотрев на эту строку, вы указали выше «@address = @ profile.addresses.new address_params ...» - я не уверен, где использовать это в моем контроллере профиля. Я не могу найти пример этого в любом из ресурсов. – Mel

+0

Я также смущен вами, комментируя, что меня путают, какая модель имеет полиморфный элемент ассоциации. Я думаю, что я правильно настроил ассоциации - я не вижу разницы между вашим примером и моим кодом – Mel

Смежные вопросы