Rails 3.2.2 Вложенная модель простой формы (через has_many) работает, но хочет улучшить - PullRequest
2 голосов
/ 02 апреля 2012

Используя гем simple_forms в Rails 3.2.2, я создал форму для создания объектов во вложенной модели (еще раз спасибо Райану Бейтсу на railscasts.com), но я изо всех сил пытаюсь освоить сложность отношения has_many черезбез добавления дополнительного кода к методу создания моего игрового контроллера.

Я использую accepts_nested_attributes_for: участники моей игровой модели с надеждой на возможность массового назначения 2 необходимых объектов участника.

У меня есть три класса: Игра, Команда и Сквозной стол. Участник

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

В настоящее время яиспользуя select_tag в форме, чтобы создать пару параметров psuedo, которые я затем использую для создания участников в методе create в контроллере, после того как я сохраню новый объект @game, я создаю @ game.participant для домашней команды икоманда гостейЭто все работает, но это слишком тяжело и не может быть расширено, если я, например, хотел создать турнир по играм без написания большего количества кода контроллера.

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

ОК ... проблемы ...

  1. builder.input: team_id,: collection => Team.all

    Это помещает идентификатор объекта в селектор, я хочу, чтобы Team.full_name создавалось в текущем "select_tag" home", options_from_collection_for_select (Team.all,: id,: full_name) и идентификатор, который нужно вставить в параметр team_id.Я изо всех сил пытаюсь найти приличную документацию simple_forms, и просмотр источника gem доставил мне головную боль (я не достаточно хорош, чтобы расшифровать его)

  2. Мне нужно различать двух участниковсозданный в новом игровом объекте.Simple_form f.simple_fields_for: участники делают | строитель |не позволит мне делать: members.first или: members.last.Я хочу создать скрытое поле, устанавливающее для: home_team значение true для первого участника.

Если я смогу заставить эти две части работать, то я думаю, что мое решение будет работать.Любая помощь или подсказки, как всегда, очень ценятся.

Модель игры:

class Game < ActiveRecord::Base
  belongs_to :venue
  belongs_to :game_type
  has_and_belongs_to_many :tournaments
  has_many :participants, :dependent => :destroy
  has_many :teams, :through => :participants

  validates :kickoff, :venue_id, :presence => true
  accepts_nested_attributes_for :participants,
    :reject_if => lambda {|a| a[:game_id].blank? },
       :allow_destroy => :true
  def home_team
    self.teams.joins(:participants).where("participants.home_team = ?", true).first
  end
  def away_team
    self.teams.joins(:participants).where("participants.home_team = ?", false).first
  end
end

Модель участника:

class Participant < ActiveRecord::Base
  belongs_to :game
  belongs_to :team
end

Модель команды:

class Team < ActiveRecord::Base
  has_many :participants, :dependent => :destroy
  has_many :games, :through => :participants
  validates :full_name, :presence => true
  validates :short_name, :presence => true, :length => { :within => 1..5 }
end

Игровой контроллер (методы создания и создания)

class GamesController < ApplicationController
  def new
    @game = Game.new
    ### This section is not currently implemented
    # 2.times { @game.participants.build }
    ### End of unimplemented section
    respond_to do |format|
      format.html # new.html.erb
    end
  end

  def create
    @game = Game.new(params[:game])
    respond_to do |format|
    if @game.save
      @game.participants.create(:team_id => params[:home], :home_team => true)
      @game.participants.create(:team_id => params[:away], :home_team => false)
      format.html { redirect_to games_path, notice: 'Game was successfully created.' }
    else
      format.html { render action: "new" }
    end
  end
end

Форма просмотра игр Частичная (на самом деле есть еще одна частичная, но включенная для удобства чтения)

<%= simple_form_for(@game) do |f| %>
  <%= f.error_notification %>   
  <div class="form-inputs">
    <%= label_tag "home", "Home Team"%>
    <%= select_tag "home", options_from_collection_for_select(Team.all, :id, :full_name)%>
    <!-- This section is not working properly -->
    <!-- <%=# f.simple_fields_for :participants do |builder| %> -->
      <!-- <%=# builder.input :team_id, :collection => Team.all, :selected => :full_name %> -->
    <!-- <%# end %> -->
    <!-- End of not working properly section -->
    <%= f.input :home_goals, :input_html => {:maxlength => 5, :size => 5 }%>
    <%= f.input :away_goals, :input_html => {:maxlength => 5, :size => 5 }%>
    <%= select_tag "away", options_from_collection_for_select(Team.all, :id, :full_name)%>
    <%= label_tag "away", "Away Team"%>
    <%= f.input :kickoff %>
    <%= f.input :completed %>
    <%= f.input :game_type_id %>
    <%= f.input :venue_id ,:collection => Venue.all, prompt:  'Choose the venue'%>
  </div> 
  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>

1 Ответ

3 голосов
/ 03 апреля 2012

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

  1. Использовал возможности сбора в классе, а не какие-либо помощники simple_form, поэтому в представлении игрЧастичная форма имела следующие изменения в строке сбора:

    <%= builder.input :team_id, :collection => Team.all.collect{ |t| [t.full_name, t.id ]}%>
    
  2. Я использовал сравнение счетчиков, чтобы установить достоверность, отмечая значение скрытого поля.Это не очень объектный код, но означает, что код работает с использованием помощников simple_form, а контроллер просто использует .save (при создании) и update_attributes (при обновлении) без какого-либо дополнительного кода.Очень хорошо.Также немного исправлен accepts_nested_attributes_for, чтобы искать пустой team_id, а не game_id (который никогда не будет пустым!).Теперь код выглядит следующим образом ...

Модель игры:

    class Game < ActiveRecord::Base
      belongs_to :venue
      belongs_to :game_type
      has_and_belongs_to_many :tournaments
      has_many :participants, :dependent => :destroy
      has_many :teams, :through => :participants

      validates :kickoff, :venue_id, :presence => true

      accepts_nested_attributes_for :participants,
        :reject_if => lambda {|a| a[:team_id].blank? },
          :allow_destroy => :true

      def home_team
        self.teams.joins(:participants).where("participants.home_team = ?", true).first
      end

     def away_team
       self.teams.joins(:participants).where("participants.home_team = ?", false).first
     end
   end

Контроллер игр (методы создания и создания)

    class GamesController < ApplicationController
      def new
        @game = Game.new
        2.times { @game.participants.build }
        respond_to do |format|
          format.html # new.html.erb
        end
      end
      def create
        @game = Game.new(params[:game])
        respond_to do |format|
          if @game.save
            format.html { redirect_to games_path, notice: 'Game was successfully created.' }
          else
            format.html { render action: "new" }
          end
        end
      end
    end

Форма просмотра игр Частичная (на самом деле есть другая частичная, но включенная для удобства чтения)

    <%= simple_form_for(@game) do |f| %>
      <%= f.error_notification %>
    <div class="form-inputs">
      <% count = 0 %>
      <%= f.simple_fields_for :participants do |builder| %>
        <% if count == 0 %>
          <% value = true %>
          <% count += 1 %>
        <% else %>
          <% value = false%>
        <% end %>
        <%= builder.input :home_team, :as => :hidden, :input_html => {:value => value} %>
        <%= builder.input :team_id, :collection => Team.all.collect{ |t| [t.full_name, t.id ]}%>
      <% end %>
      <%= f.input :home_goals, :input_html => {:maxlength => 5, :size => 5 }%>
      <%= f.input :away_goals, :input_html => {:maxlength => 5, :size => 5 }%>
      <%= f.input :kickoff %>
      <%= f.input :completed %>
      <%= f.input :game_type_id %>
      <%= f.input :venue_id ,:collection => Venue.all, prompt:  'Choose the venue'%>
    </div>
    <div class="form-actions">
       <%= f.button :submit %>
    </div>
  <% end %>

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

С уважением

Peter

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...