-1

I am stuck on a problem which I just can't get a good solution to, and hope someone with more experience than me can help.

I'm creating a rails app where you can register matches in a game, and you pick which players were participants in that match by selecting from drop down lists. I am doing this by using form_for with nested fields_for.

<%= form_for [@group, @match] do |f| %>
  <table class="table" id="match_players">
    <tr>
      <th>Placement</th>
      <th>Player</th>
    </tr>
    <%= create_player_in_match_row(f, 1, @group.active_players) %>
    <%= create_player_in_match_row(f, 2, @group.active_players) %>
  </table>
  <a id="add_player_row">Add Player</a>
  <%= f.submit("Create") %>
<% end %>

The create_player_in_match_row method is for creating a row with a dropdown. The code is in a helper class and it looks like this:

def create_player_in_match_row(form, nr, players)
  form.fields_for :player_in_matches, @match.player_in_matches.build do |pim|
    "<tr id='row_p#{ nr }'>
      #{ pim.hidden_field "placement", value: nr }
      <td>#{ nr }.</td>
      <td>#{ player_select_tag(pim, players) }</td>
      <td>#{ tie_check_box(pim) }</td>
    </tr>".html_safe
  end
end

def player_select_tag(pim, players)
  players = players.order "name ASC"
  pim.select :player_id,
             players.map { |p| [p.name, p.id] },
             { include_blank: false },
             { class: 'chosen-select' }
end

The problem: As you can see in the form_for I've got a link "Add Player". I want this button to add a new row with a dropdown for choosing players.

As of now I am creating a new row in coffeescript with something like this:

$("#add_player_row").click ->
  select_row_original = document.getElementById('row_p1')
  new_select_row = select_row_original.cloneNode(true)
  new_select_row_placement = document.getElementsByClassName('player_row').length + 1

  # Change A LOT of ids and stuff

  $("#match_players").append(new_select_row)

But this feels hacky and has really unintuitive code. Can someone point me in the direction of a smarter solution? Is there some way I can reuse the helper class method for adding row?

ghdalum
  • 891
  • 5
  • 17

1 Answers1

1

As a reference, this RailsCast, #196 - Nested Model Form (revised) provides the most updated answer to your problem.

But you can see:

Which can give you a (somewhat outdated) idea of better ways to handle your problem.

Now, to your code:

  1. As a first suggestion, it's probably better in this case to use ul's instead of table (and for layout purposes in general).

  2. Avoid using SQL queries in views or helpers, queries always belong in the models.

For instance, you can use a scope for players ordered by name in your Player model:

    class Player < ActiveRecord::Base
      scope :name_ordered, -> { order(:name) }
    end
  1. Then you can load an instance variable @players from your Controller, and use it in the view.

  2. Use HTML in Ruby code is difficult to read, and you may end up with escaping \", it's better to use content_tag. See this example. If you need to concatenate several tags inside, use concat. An example (it may not be a 100% correct, but you'll get the idea):

    player_select = pim.select @players, :id, {include_blank: false}, {class: 'chosen-select'}) content_tag :tr, id: "row_p#{nr}" do concat(pim.hidden_field "placement", value: nr) concat(content_tag :td, "#{nr}") concat(content_tag :td, player_select) # ... end

You can see Rails Guides - Form Helpers for more information.

Hope this helps!

Community
  • 1
  • 1
raviolicode
  • 2,155
  • 21
  • 22
  • Hey. Thank you for your answer. The railscast 196 revised helped me and I now got it working. Also thank you for your general code improvement tips. I have upvoted your answer, but I won't mark the answer as the accepted answer as it requires payment to an external site to get the actual answer. – ghdalum Aug 13 '14 at 08:59
  • I tried the free episodes first but did not get it to work, and ended up paying the subscription. It does not provide an answer for other people finding this question either, since they also may have to pay subscription to RailsCasts (which they in the future have to do even though free episodes are working for them right now, since the free epiodes contains usage of Rails functionality that are deprecated). – ghdalum Aug 14 '14 at 06:10