简体   繁体   中英

Rails - pass a parameter to controller from form select dropdown

I have 2 models: Team and Quest . When creating a new team, I have a drop-down of all the quests. When a quest is selected, I want to display information about the quest.

My understanding is that everything in the form is on the client side and AJAX is required to pass the selected quest to the server side. My code is based on this Stack Overflow answer.

Here is how I constructed my form:

app/views/teams_form.html.erb

<%= form_for(@team) do |f| %>
  <fieldset>
    <ol>
      <li>
        <%= f.label :name %>
        <%= f.text_field :name %>
      </li>
      <li>
        <%= f.label :quest_id %>
        <%= f.select :quest_id, 
                     options_from_collection_for_select(@quests, :id, :name), 
                     {}, {remote: true, url: '/teams/new', method: 'get'} %>
      </li>
      <% if @x != nil && @x.id != nil %>
        <li><%= @x.id %></li>
      <% end %>
    </ol>
    <p>
      <%= f.submit %>
    </p>
  </fieldset>
<% end %>

app/controllers/team_controller.rb

def new
  @team = Team.new
  @quests = Quest.all
  respond_to do |format|
    if params[:quest_id] != nil
      @x = Quest.find(params[:quest_id])
    end
    format.html #new.html.erb
    format.json
    format.js
  end
end

My goal was to pass the :quest_id parameter from the form to the @x variable and use that in the form.

This has produced nothing. I'm not getting the parameter in the controller and I'm not sure what I'm missing.

As per the description shared it seems like the you are unable to get the value of the selected item from the dropdown.

Below mentioned code is used for selecting value from dropdown also you can inspect the same using developer tools of the browser.

quest = $("#quest_id").val();

Note: Assuming the selector id is quest_id, change it according to your form.

Now, you can call the ajax using the below mentioned code.

$.ajax({
  type: "GET",
  url: "/teams/new",
  data:{ quest_id: quest },
  dataType: "json",
  success:function(data){
    # logic for using ajax result
  }

Hope it helps!!

Finally got this working, wanted to post if anyone sees this and is having the same problem:

I went with a separate AJAX request since that was being suggested

app/views/teams_form.html.erb

<script>
   $(document).ready(function() {
    $('#team_quest_id').change(function() {
       $.ajax({
         url: "/teams/new",
         data: {quest_id: $("#team_quest_id option:selected").val()},
         dataType: "script",
         method: "get",
         success: function(r){}
       });
     });
   });
</script>

I moved the location of the parameter assignment

app/controllers/team_controller.rb

def new
  @team = Team.new
  @quests = Quest.all
  if params[:quest_id] != nil
    @x = Quest.find(params[:quest_id])
  end
  respond_to do |format|
    format.html #new.html.erb
    format.json
    format.js
  end
end

And most importantly - I created a js file to render my form

app/views/new.js.erb

$('#new_team').html("<%= j (render 'form') %>");

This video was extremely helpful

The code in your question is almost correct, you forgot to nest the attributes in data .

<% # app/views/teams_form.html.erb %>

<%= f.select :quest_id, 
                     options_from_collection_for_select(@quests, :id, :name), 
                     {}, {remote: true, url: '/teams/new', method: 'get'} %>
<% # should be: %>
<%= f.select :quest_id, 
                     options_from_collection_for_select(@quests, :id, :name), 
                     {}, {data: {remote: true, url: '/teams/new', method: 'get'}} %>
<% # or even better, use the path helper instead of the hard coded path %>
<%= f.select :quest_id, 
                     options_from_collection_for_select(@quests, :id, :name), 
                     {}, {data: {remote: true, url: new_team_path, method: :get}} %>

Having set the attributes correctly, we still need to fix the form further. On page request the browser will request the form, but @x will never be set. Since ERB will not be send to the client we'll need to add a handle to find our quest container element back.

<% # app/views/teams_form.html.erb %>

<% if @x != nil && @x.id != nil %>
  <li><%= @x.id %></li>
<% end %>
<% # should be something like %>
<li id="quest-info-container"></li>

Now in the controller split of the HTML request from the JS request.

# app/controllers/teams_controller.rb

def new
  respond_to do |format|
    format.html do
      @team = Team.new
      @quests = Quest.all
    end
    format.js do
      @quest = Quest.find(params.dig(:team, :quest_id))
    end
  end
end

You could simplify the above by sending the select data-path to another url that handles the quest preview.

Now we need to render the preview in our container we need 2 files for this, first of how the resulting structure should look. Keep in mind that this will be rendered inside the container.

<% # app/views/teams/_quest_preview.html.erb %>

<% # Here comes what you want to display about the quest. You can give this %>
<% # file another name if you like. You have @quest to your disposal here. %>
<%= @quest.id %> <strong><%= @quest.name %></strong>

Now we only need a JavaScript file that loads the above structure into our created handle.

<% # app/views/teams/new.js.erb %>

handle = document.getElementById('quest-info-container');
handle.innerHTML = '<%= j render('quest_preview') %>';

The j is an alias for escape_javascript . If the partial is not in the same directory use <%= j render('other_dir/some_partial') %> instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM