Liz Liz - 7 months ago 7
Ruby Question

Ruby Problems Displaying Variables From New View, but Not Edit

In my app I have a quiz in a partial because I need the same (lengthy) quiz for my

new
and for my
edit
view. In the header of the
application.html.erb
and on my
users#show
page I display the results from this quiz, once it is taken, using an if/else statement. For some reason, after a user takes the quiz in the
new
view it is registering that the quiz has been completed (you can tell by the if/else statement) but not displaying the variables. However, using the
edit
view (that calls the same partial
_quiz.html.erb
) the variables display perfectly.

My
new
view calls the partial like this:

<%= render partial: "quiz", locals: { url: swing_books_path, method: :post } %>


While my
edit
view calls it like this:

<%= render partial: "quiz", locals: { url: edit_swing_book_path(@swing_book), method: :put } %>


The partial looks like this:

<%= form_for @swing_book do |f| %>
<div class="clearfix">
<h1 class="text-center">
<%= f.text_field :swing01, class: 'form-control input-1' %>
<%= f.text_field :swing02, class: 'form-control input-1' %>
<%= f.text_field :swing03, class: 'form-control input-1' %>
-
<%= f.text_field :swing04, class: 'form-control input-1' %>
<%= f.text_field :swing05, class: 'form-control input-1' %>
<%= f.text_field :swing06, class: 'form-control input-1' %>
-
<%= f.text_field :swing07, class: 'form-control input-1' %>
<%= f.text_field :swing08, class: 'form-control input-1' %>
<%= f.text_field :swing09, class: 'form-control input-1' %>
<%= f.text_field :swing10, class: 'form-control input-1' %>
</h1>

<div class="form-group text-center">
<%= f.submit "Submit Swing Code", class: 'btn btn-success' %>
</div>
</div>
<% end %>


However, I use these exact same details (with just the variable names changed) on another quiz that is not having the same issue. (I have three other similar quizzes all of which display perfectly from both
new
and
edit
views.)

My model looks like this:

class SwingBook < ActiveRecord::Base
before_save :set_swing_code

def set_swing_code
self.swing_code = "#{self.swing01}#{self.swing02}#{self.swing03}-#{self.swing04}#{self.swing05}#{self.swing06}-#{self.swing07}#{self.swing08}#{self.swing09}#{self.swing10}"
end

belongs_to :user
validates :user, presence: true
end


My controller looks like this:

class SwingBooksController < ApplicationController
before_action :require_sign_in

def show
@swing_book = SwingBook.find(params[:id])
end

def new
@swing_book = current_user.build_swing_book
end

def create
@swing_book = SwingBook.new

@swing_book.swing_code = params[:swing_book][:swing01]
@swing_book.swing_code = params[:swing_book][:swing02]
@swing_book.swing_code = params[:swing_book][:swing03]
@swing_book.swing_code = params[:swing_book][:swing04]
@swing_book.swing_code = params[:swing_book][:swing05]
@swing_book.swing_code = params[:swing_book][:swing06]
@swing_book.swing_code = params[:swing_book][:swing07]
@swing_book.swing_code = params[:swing_book][:swing08]
@swing_book.swing_code = params[:swing_book][:swing09]
@swing_book.swing_code = params[:swing_book][:swing10]
@swing_book.swing_code = params[:swing_book][:swing_code]

@swing_book.user = current_user

if @swing_book.save
flash[:notice] = "Your swing code was saved successfully."
redirect_to user_path(current_user)
else
flash[:alert] = "Sorry, your results failed to save."
redirect_to welcome_index_path
end
end

def edit
@swing_book = SwingBook.find(params[:id])
end

def update
@swing_book = SwingBook.find(params[:id])

@swing_book.assign_attributes(swing_book_params)

if @swing_book.save
flash[:notice] = "Results were updated successfully."
redirect_to user_path(current_user)
else
flash.now[:alert] = "There was an error saving your results. Please try again."
redirect_to welcome_index_path
end
end

private
def swing_book_params
params.require(:swing_book).permit(:swing01, :swing02, :swing03, :swing04, :swing05, :swing06, :swing07, :swing08, :swing09, :swing10, :swing_code)
end
end


Finally, here's the logic I'm using to display these variables in the
application.html.erb
file:

<% if current_user.swing_book != nil %>
<p>ID Code:
<%= current_user.swing_book.swing01 %>
<%= current_user.swing_book.swing02 %>
<%= current_user.swing_book.swing03 %>
-
<%= current_user.swing_book.swing04 %>
<%= current_user.swing_book.swing05 %>
<%= current_user.swing_book.swing06 %>
-
<%= current_user.swing_book.swing07 %>
<%= current_user.swing_book.swing08 %>
<%= current_user.swing_book.swing09 %>
<%= current_user.swing_book.swing10 %></p>
<% end %>


And on the
user#show
page:

<% if @user.swing_book == nil %>
<h3>ID Code: ???-???-????<%= %></h3>
<p><%= link_to "Get Your ID Code Now!", new_swing_book_path %></p>
<% else %>
<h3>ID Code:
<%= @user.swing_book.swing01 %>
<%= @user.swing_book.swing02 %>
<%= @user.swing_book.swing03 %>
-
<%= @user.swing_book.swing04 %>
<%= @user.swing_book.swing05 %>
<%= @user.swing_book.swing06 %>
-
<%= @user.swing_book.swing07 %>
<%= @user.swing_book.swing08 %>
<%= @user.swing_book.swing09 %>
<%= @user.swing_book.swing10 %></h3>
<p><%= link_to "Update Your Code", edit_swing_book_path(@user.swing_book) %></p>
<% end %>


I originally tried displaying just the
swing_code
variable (as established in the
method
, but it was displaying a single integer so I switched to the code seen above. Ideally, I would like to display it as just the
swing_code
variable, but the (somewhat repetitive) workaround I'm currently using works fine-ish if I could only get the
new
/
edit
display issue worked out.

Any ideas as to what could be going wrong? I can't find any differences between this and the other quizzes that could be causing a problem!

Answer

In your create method, you have a block of code that explicitly sets the @swing_book values. This code is setting all of the values from the form into just the swing_code member. Since the last assignment is also from the swing_code param to the swing_code member, it's hiding the mistake. Here's the code with the correct member fields assigned:

@swing_book.swing01 = params[:swing_book][:swing01]
@swing_book.swing02 = params[:swing_book][:swing02]
@swing_book.swing03 = params[:swing_book][:swing03]
@swing_book.swing04 = params[:swing_book][:swing04]
@swing_book.swing05 = params[:swing_book][:swing05]
@swing_book.swing06 = params[:swing_book][:swing06]
@swing_book.swing07 = params[:swing_book][:swing07]
@swing_book.swing08 = params[:swing_book][:swing08]
@swing_book.swing09 = params[:swing_book][:swing09]
@swing_book.swing10 = params[:swing_book][:swing10]
@swing_book.swing_code = params[:swing_book][:swing_code]

Now, while that will fix the immediate problem, you probably just want to use the same approach as the update method. Try this for your create method, instead:

def create
  @swing_book = SwingBook.new

  @swing_book.assign_attributes(swing_book_params)
  @swing_book.user = current_user

  if @swing_book.save
    flash[:notice] = "Your swing code was saved successfully."
    redirect_to user_path(current_user)
  else
    flash[:alert] = "Sorry, your results failed to save."
    redirect_to welcome_index_path
  end
end

However, you have an opportunity to minimize the overall code to help eliminate errors like this. Consider something like this for your controller code:

class SwingBooksController < ApplicationController
  before_action :require_sign_in

  def show
    @swing_book = SwingBook.find(params[:id])
  end

  def new
    @swing_book = current_user.build_swing_book
  end

  def edit
    @swing_book = SwingBook.find(params[:id])
  end

  def create
    @swing_book = SwingBook.new
    apply_form_values
  end

  def update
    @swing_book = SwingBook.find(params[:id])
    apply_form_values
  end

private
  def apply_form_values
    @swing_book.assign_attributes(swing_book_params)

    if @swing_book.save
      flash[:notice] = "Results were updated successfully."
      redirect_to user_path(current_user)
    else
      flash.now[:alert] = "There was an error saving your results. Please try again."
      redirect_to welcome_index_path
    end
  end

  def swing_book_params
    params.require(:swing_book).permit(:swing01, :swing02, :swing03, :swing04, :swing05, :swing06, :swing07, :swing08, :swing09, :swing10, :swing_code)
  end
end

You can use techniques like this to make it easier to write your initial code, and make it far easier to maintain.