RAILS Как я могу создать вложенную форму для изменения has_many с помощью логического атрибута связанного объекта с помощью флажков?

У меня есть 3 модели: User, Profile и Photo.

Profile < ApplicationRecord
 belongs_to :user
 has_many :photos, through: :user

Photo < ApplicationRecord
 belongs to :user

User < ApplicationRecord
 has_one :profile
 has_many :photos

Я хотел бы создать форму для @profile, которая также отображает флажки для всех связанных фотографий.

Когда фотография проверена, я бы хотел, чтобы #featured_status этой фотографии превратился в TRUE. (в моей базе данных он имеет значение по умолчанию 1).

Класс Photo имеет эти методы

class Photo < ApplicationRecord
 belongs_to :user


 has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
 validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
 validates :image, :title, :description, presence: true

 FEATURED_STATUS = { not_featured: 0, featured: 1 }

 def featured?
  self.featured_status == FEATURED_STATUS[:featured]
 end

 def not_featured?
  self.featured_status == FEATURED_STATUS[:not_featured]
 end

 def myPhoto
  ActionController::Base.helpers.image_tag("#{image.url(:thumb)}")
 end

end

Как я могу построить эту форму?

Я пробовал разные варианты использования fields_for, collection_check_boxes, check_boxes, и я не могу правильно зафиксировать информацию.

На данный момент это моя форма.

<%= simple_form_for @profile do |f| %>

<%= f.input :bio, input_html: { class: 'form-control'} %>

    <section class="main">
        <label>Featured Profile Photos</label>
        <% @profile.photos.each do |photo| %>
            <%= form_for ([@profile, photo]) do |f| %>
                <%= f.check_box :featured_status, :checked => (true if photo.featured?) %>
                <%= f.submit %>
                <% end %>
            <label><%= photo.myPhoto %></label>
        <% end %>
    </section>

<%= f.button :submit %>

Когда форма отображается, появляется несколько кнопок «обновить» — по одной для каждой фотографии. Я также не могу отправить изменения @profile.bio одновременно с обновлением Featured_status фотографии.

В идеале я хотел бы, чтобы каждая из этих кнопок обновления фотографий была скрыта, и была только одна кнопка отправки, которая обновляет биографию профиля: текст и отображает @profile.

В то же время, я бы хотел, чтобы photo.featured_status менял значение true/false, как только флажок был установлен. (Может быть, с помощью Javascript?)

Любые предложения действительно ценятся.


comment
Можете ли вы дать более подробную информацию об ассоциации между моделями? Одного не хватает. Вы имеете в виду что-то похожее на edgeguides.rubyonrails.org/< /а>?   -  person iGian    schedule 01.07.2018
comment
Привет да! Вот такая же ассоциация. Модель пользователя имеет_много фотографий и имеет_один профиль.   -  person Kim    schedule 01.07.2018
comment
Почему вы заявили, что Photo has_one profile ? Фото уже является дочерним элементом профиля. На самом деле это не может быть и родительским, и дочерним. (ну, может быть, но вы увидите это позже, особенно для моделей комментариев, где комментарий может быть родителем другого комментария, но также и дочерним элементом комментария, но для этого нужна конкретная формулировка)   -  person Maxence    schedule 01.07.2018
comment
Кажется, что-то не так с вашим кодом, если User является таблицей соединений, а вы используете ассоциацию has_many :through.   -  person iGian    schedule 01.07.2018
comment
@iGian прав: в edgeguide Appointments являются дочерними элементами как Patients, так и Physicians. В дизайне вашего приложения. один Photo, вероятно, может принадлежать Profileи User, хотя User уже принадлежит Profile. Users и profiles не являются двумя отдельными объектами, как в руководстве, но уже связаны в вашем дизайне. Пожалуйста, объясните, что такое Пользователи и Профили, их различие, и мы постараемся рассказать вам о правильных отношениях.   -  person Maxence    schedule 01.07.2018
comment
Думаю, я понимаю, что вы имеете в виду. Было бы правильно, если бы я изменил свою ассоциацию с фотографией на class Photo has_one :profile, inverse_of :photo? Я попытался удалить has_one и получил ошибку при вызове photo.profile. Добавление опции inverse_of, казалось, облегчило ситуацию.   -  person Kim    schedule 01.07.2018
comment
Просто подумайте об ассоциациях как о дереве предков. Я не уверен, что Photo должен чем-то владеть. Фотография — это то, что принадлежит профилю, пользователю, продукту, компании... Я не уверен, что оно должно принадлежать кому-либо из них.   -  person Maxence    schedule 01.07.2018
comment
Я хотел иметь исключительно модель профиля. В отличие от модели пользователя, которая используется исключительно для входа в систему и публикации фотографий, модель профиля имеет атрибут bio:string и фотографии (по наследованию пользователя). Фотомодель имеет следующие атрибуты: заголовок: строка, описание: текст, изображение (загруженный файл) и Featured_status: целое число (по умолчанию 1). Я хотел, чтобы форма редактирования профиля имела входные данные для изменения profile.bio И имела флажки рядом с каждой связанной фотографией этого профиля. Когда кто-то проверяет/снимает отметку с фотографии, я бы хотел, чтобы для параметра Featured_status фотографии было установлено значение 0/1.   -  person Kim    schedule 01.07.2018
comment
Кроме того, спасибо, Максенс, я удалил has_one из Photo и вместо этого просто назвал photo.user.profile.   -  person Kim    schedule 01.07.2018


Ответы (2)


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

User
has_one :profile
has_many :photos

Profile
belongs_to :user

Photo
belongs to :user 

Теперь вы можете решить, где вы хотите включить или отключить редактирование отображения фотографий. Либо в действии «Редактирование пользователей», наряду с другими данными пользователя, либо даже с данными профиля. Или, может быть, создав определенное действие в контроллере фотографий (действие редактирования обычно предназначено для редактирования одного экземпляра, а не всех экземпляров для конкретного пользователя, которых должно быть несколько)

Затем, если у вас есть реальный код и представления, вы можете пойти дальше.

person Maxence    schedule 30.06.2018
comment
Спасибо, Максенс, я добавил дополнительный код в свой исходный вопрос выше. Пожалуйста, дайте мне знать, если у вас есть какие-либо предложения. Я ценю, что вы нашли время! Связь profile.photos предназначена для выполнения требований проекта для школы. Мне нужна вложенная форма - person Kim; 01.07.2018

приложение/models/profile.rb:

class Profile < ApplicationRecord
  has_one :user
  has_many :photos, through: :user
  accepts_nested_attributes_for :photos
end

приложение/контроллеры/profiles_controller.rb:

class ProfilesController < ApplicationController
  before_action :set_profile, only: [:update] # etc...

  def update
    if @profile.update(profile_params)
      # success, do something; i.e:
      # redirect_to @profile, notice: 'Profile has been updated'
    else
      # validation errors, do something; i.e:
      # render :edit
    end
  end

  private

  def set_profile
    @profile = Profile.find(params[:id])
  end

  def profile_params
    params.require(:profile).permit(:bio, photos_attributes: [:id, :featured_status]) # etc...
  end
end

приложение/представления/профили/_form.html.erb

<%= simple_form_for @profile do |f| %>
  <%= f.input :bio, input_html: { class: 'form-control'} %>

  <section class="main">
    <label>Featured Profile Photos</label>

    <%= f.simple_fields_for :photos do |ff| %>
      <%= ff.check_box :featured_status %>
      <label><%= ff.object.myPhoto %></label>
    <% end %>
  </section>

  <%= f.button :submit %>
<% end %>

Рекомендации:

  • Подобно другим комментариям от Maxence и iGian, я бы посоветовал что-то вроде следующего:

    • User has_many / has_one Profiles
    • Профиль has_many Фото

    ... вместо:

    • Профиль has_one Пользователь
    • Профиль has_many Фото

    ... по той единственной причине, что интуитивно говоря, я думаю, что пользователь (тот, кто входит в систему) может иметь один или несколько профилей, из которых тогда профиль должен принадлежать пользователю. В настоящее время у вас есть профиль has_one User, который всегда будет работать в любом случае, где будет external_key (либо пользователь, либо профиль в порядке), но что я обычно делаю, чтобы узнать, где находится foreign_key, так это принять во внимание возможный будущее изменение: (т. е. has_one становится has_many), и поэтому теперь, когда я установил это, для Пользователя имеет больше смысла иметь много Профилей, а не Профиль, чтобы иметь много Пользователей. Конечно, если вы намеренно хотите этого и знаете о реализации вашей схемы, то это всегда правильный способ сделать это (в зависимости от ваших предпосылок) :)

Использованная литература:

person Jay-Ar Polidario    schedule 01.07.2018
comment
Я только что заметил, что вы используете Profile has_one User, но в то же время User has_one Profile. Только один из них должен быть has_one, а другой должен быть created_to, а не оба has_one друг у друга. Я не знаю, куда вы поместили сторонний_ключ, т.е. у вас есть столбец user_id в таблице профилей? (тогда это должно быть Профиль принадлежит_к: пользователю), или... у вас есть столбец profile_id в таблице пользователей? (тогда это должен быть пользователь, принадлежащий_к: профиль. Теперь мое решение выше предполагает, что у вас есть столбец profile_idв таблице пользователей. - person Jay-Ar Polidario; 01.07.2018
comment
Моя ошибка! Да, я реализовал Профиль принадлежит одному пользователю. Я некоторое время смотрел на свой код, поэтому мой мозг тает. Мой внешний ключ находится в модели профиля. - person Kim; 01.07.2018
comment
Я вижу, поскольку это профиль принадлежит пользователю, я думаю, что мое решение выше все равно будет работать, потому что я только что посмотрел на это SO post, потому что кажется, что вложенные атрибуты также работают для own_to в Rails ›= 4. Если нет, дайте мне знать, я попробую проверить это сам, когда получу время. - person Jay-Ar Polidario; 01.07.2018
comment
Привет Джей! Миллион раз благодарю вас за эти рекомендации, я пытаюсь работать над этой функцией уже несколько дней. Я реализовал ваши рекомендации для формы вместе с контроллером профиля в Т. Форма кажется идеальной для того, что я хотел отобразить. Однако при отправке я получаю сообщение об ошибке, и изменения фотографии не сохраняются. - person Kim; 01.07.2018
comment
Полные ошибки сообщения: photos.user must exist, photos.image can't be blank, photos.title can't be blank . Это мои уникальные фото-проверки. Я не уверен, но кажется, что форма передает методу целую коллекцию фотографий (photos.user вместо photo.user), а не отдельную...? Вы знаете, как я могу это исправить? Это как-то связано с моими отношениями с Фото профиля? - person Kim; 01.07.2018
comment
исходный код находится здесь на github, если это поможет. Большое спасибо, Джей-Ар github.com/KimGonzales/inscape/tree/featured-photos - person Kim; 01.07.2018
comment
@Kim Я только что отправил вам Git Pull Request для вашего проекта. Нажмите на вкладку [Файлы изменены], и вы увидите изменения. В основном только то, что я забыл добавить :id к photos_attributes выше. Я протестировал эту работу, но вам нужно будет добавить/объединить с вашим текущим локальным кодом, потому что я предположил, что ваш локальный код уже имеет столбец Featured_status в таблице фотографий, потому что ваша удаленная основная ветка в настоящее время еще не имеет его :) Дайте мне знать, если вы все еще сталкиваетесь с проблемами. - person Jay-Ar Polidario; 01.07.2018
comment
Джей-Ар, ты бомба. Большое спасибо, это сработало прекрасно. - person Kim; 02.07.2018