Rails deeply nested resources alternative to accessing params

282 views Asked by At

I have an event model and a Q+A model inside the event.

I'm new to rails so not sure if there is an alternate way to do this

Right now, inside an event show.html.erb, I have both a form to post a question, and each question will have a form to post an answer

The routes sit like this right now

  resources :events do
    resources :event_questions, only: [:create, :destroy]
  end

When you create a question inside my show.html.erb, it's being routed through EventQuestionsController and I access the event_id via params. Do I have to do it the same way with my event_answer?

And by that I mean, do I have to nest event_answers inside event_questions. I will need to know the event_id and the event_question_id.

If that's the only way to access the params. Would it look like this?

  resources :events do
    resources :event_questions, only: [:create, :destroy] do
       resources :event_answers, only: [:create, :destroy]
    end
  end

event_questions_controller.rb

def create
    @event_question = EventQuestion.new(event_question_params)
    if @event_question.save
        event = Event.find(params[:event_id])
        @event_question.event = event
        redirect_to event
    else
        redirect_to :back
    end
end

show.html.erb

<%= form_for(@event_question, :url => event_event_questions_path(@event)) do |f|  %>
# form stuff
<% end %>

I started changing my answer form to this

<%= @event.event_questions.each do |q| %>
    <%= q.question %>
    <%= q.fields_for :answers do |a| %>
        <%= a.label :answer %>
        <%= a.text_field :answer %>
        <%= a.submit "Answer" %>
    <% end %>
<% end %>
2

There are 2 answers

0
Clam On BEST ANSWER

With some help I derived this answer from a bit of kobaltz answer and some other help.

The alternate method would be putting the information in hidden fields and passing it to the controller

   <%= @event.event_questions.each do |q| %>
        <%= q.question %><br>
        <% q.event_answers.each do |a| %>
            <%= a.answer %>
        <% end %>
        <%= form_for(EventAnswer.new) do |f| %>
            <%= hidden_field_tag :event_question_id, q.id %>
            <%= hidden_field_tag :event_id, @event.id %>
            <%= f.label :answer %>
            <%= f.text_field :answer %>
            <%= f.submit "Answer" %>
        <% end %>
    <% end %>
1
kobaltz On

You shouldn't need to directly access the params to create your nested records. For example, if in your event#new action, you may have something like

@event = Event.new

3.times do
  question = @event.questions.build
  5.times do
    question.answers.build
  end
end

This will create a new Event and take you to the New page. Within your New page, you should have nested fields to create and update the nested models.

In the form, you can use fields_for to access the associated model's records to that event record. In the new action case, we are building 3 questions and each question has 5 answers.

<%= simple_form_for @event do |f| %>
  <%= f.input :attribute1 %>
  <%= f.input :attribute2 %>
  <%= f.fields_for :questions do |builder| %>
    <%= render 'questions', f: builder %>
  <% end%>
<% end %>

I generally like to use a partial when doing nested associations, but if you wanted to keep it all in one file (see below), it would looks something like this.

<%= simple_form_for @event do |f| %>
  <%= f.input :attribute1 %>
  <%= f.input :attribute2 %>
  <%= f.fields_for :questions do |q| %>
    <%= q.input :question_text %>
    <%= q.fields_for :answers do |a| %>
      <%= a.input :answer_text %>
    <% end %>
  <% end%>
<% end %>

In your show action, you may have something like this

@event = Event.find(params[:id])
@questions = @event.questions
@answers = @question.answers if @questions

From here, you have three instance variables assigned and able to access the associated records to your events and questions.