Good afternoon people
I'm trying to build a tobacco review application, for no other reason than to learn some more stuff. I've been trying to build upon what I’ve learned in the Rails Tutorial book, however I keep coming up against brick walls and gotchas that I don't understand. I can normally get over the undefined method `something' for nil:NilClass and other issues i have, but this one's really get me stumped because I’ve got my tests passing.
My Tests
review_test.rb
require 'test_helper'
class ReviewTest < ActiveSupport::TestCase
# Define a user for the test
def setup
@user = users(:shaun)
@review = @user.reviews.build( rating: 5,
comment:"This is a super snus",
tobacco_id: 1)
end
# Test should be valid
test "should be valid" do
assert @review.valid?
end
# Test the user id is present
test "user id should be present" do
@review.user_id = nil
assert_not @review.valid?
end
# Test the tobacco id is present
test "tobacco id should be present" do
@review.tobacco_id = nil
assert_not @review.valid?
end
# Rating should be present
test "rating should be present" do
@review.rating = " "
assert_not @review.valid?
end
# Comment should be present
test "comment should be present" do
@review.comment = " "
assert_not @review.valid?
end
# Verify that the first review in the DB is the same as fixture review
test "order should be most recent first" do
assert_equal reviews(:most_recent), Review.first
end
end
user_test.rb
# Test that a review is destroyed when a user is destroyed
test "associated reviews should be destroyed" do
@user.save
@user.reviews.create!( rating: 5,
comment: "I love this suns, it's so good!",
tobacco_id: 1)
assert_difference 'Review.count', -1 do
@user.destroy
end
end
Fixtures
reviews.yml
one:
rating: 5
tobacco_id: 1
comment: "This is a super snus"
created_at: <%= 3.hours.ago %>
two:
rating: 5
tobacco_id: 1
comment: "This is the best snus in the world"
created_at: <%= 2.hours.ago %>
three:
rating: 5
tobacco_id: 1
comment: "I will always buy this snus"
created_at: <%= 1.hours.ago %>
most_recent:
rating: 5
tobacco_id: 1
comment: "I have a shed load of this snus, it's great!"
created_at: <%= Time.zone.now %>
Models
review.rb
belongs_to :tobacco
tobacco.rb
has_many :reviews
user.rb
has_many :tobaccos, dependent: :destroy
has_many :reviews, dependent: :destroy
Controller reviews_controller.rb
def new
@review = Review.new
end
This is what i have for the create action in the controller but i can't tell if i have this correct because i can't get the page to load yet. Any suggestions on the create action would be greatly appreciated to save asking another question if I have this wrong, which I probably have!
def create
@tobacco = Tobacco.find(params[:tobacco_id])
@review = @tobacco.reviews.new(params[:review].permit(:tobacco_id, :comment))
@review.user = User.find(current_user.id)
@review.save
redirect_to tobacco_path(@tobacco)
end
Routes
resources :tobaccos do
resources :reviews, except: [:show, :index]
end
show.html.erb
<%= link_to "Write a Review", new_tobacco_review_path(@tobacco) %>
new.html.erb
<%= form_for([@tobacco, @tobacco.reviews.build]) do |f| %>
<%= render 'fields', f: f %>
<%= f.submit "Save Review", class: 'btn btn-primary' %>
<% end %>
When I get to the page to write a review, i get the error
Showing C:/Sites/apps/review/app/views/reviews/new.html.erb where line #11 raised:
undefined method `reviews' for nil:NilClass
It's telling me it's line 11
<%= form_for([@tobacco, @tobacco.reviews.build]) do |f| %>
but whatever I try I get a different error. I know it's a rookie mistake but i can't see it.
Thanks in advance
Shaun
UPDATE
I've got it working and saving to the database now, i did it like this In the reviews_controller.rb the new and create look like this
def new
@tobacco = Tobacco.find(params[:tobacco_id])
end
def create
@tobacco = Tobacco.find(params[:tobacco_id])
@review = Review.new(review_params)
@review.user_id = current_user.id
@review.tobacco_id = @tobacco.id
if @review.save
redirect_to @tobacco
else
render 'new'
end
end
The review_params are
def review_params
params.require(:review).permit(:rating, :comment, :tobacco_id)
end
That all looks right to me, and it works so i hope it's all ok.
What i'm stuck on now is editing a review that belongs to a tobacco. This is the first time i've worked on nested routes. I just looked at a couple tutorials but nothing has really helped me to fix this. I am not sure how can I pass these keys...
On the show page i've got this
<%= link_to "Edit", edit_tobacco_review_path(@tobacco, @review) %>
The show method tobaccos_controller.rb looks like this
def show
@tobacco = Tobacco.find(params[:id])
@reviews = Review.where(tobacco_id: @tobacco.id)
end
In the reviews_controller.rb i've this
def edit
@tobacco = Tobacco.find(params[:tobacco_id])
@review = Review.find(params[:id])
end
And the error i'm getting is this
ActionController::UrlGenerationError in Tobaccos#show
No route matches {:action=>"edit", :controller=>"reviews", :id=>nil, :tobacco_id=>"8"} missing required keys: [:id]
Looking at this i should be doing something in the Tobaccos#show action, but i can't think what.
I'm almost home and dry, can you see what i've done wrong? Thanks :)
UPDATE NUMBER TWO show.html.erb It's not the whole show page, but it's the important part
<% if @reviews.blank? %>
<h3>No reviews yet! Would you like to be the first?</h3>
<%= link_to "Write Review", new_tobacco_review_path(@tobacco), class: "btn btn-danger" %>
<% else %>
<% @reviews.each do |review| %>
<div class="reviews">
<p><%= review.comment %></p>
<p><%= review.user.name %></p>
<%= link_to "Edit", edit_tobacco_review_path(@tobacco, @review) %>
</div>
<% end %>
<%= link_to "Write Another Review", new_tobacco_review_path(@tobacco), class: "btn btn-danger" %>
<% end %>
UPDATE NUMBER 3 edit.html.erb
<%= form_for([@tobacco, @tobacco.reviews.build]) do |f| %>
<%= render 'fields', f: f %>
<%= f.submit "Update Review", class: 'btn btn-primary' %>
<% end %>
<%= link_to "Back", tobacco_path(@tobacco),
class: "btn btn-default btn-block margin-top-25" %>
_fields.html.erb
<%= f.label :rating %>
<%= f.select :rating, [['1', 1],
['2', 2],
['3', 3],
['4', 4],
['5', 5]
] ,class: 'form-control' %>
<%= f.label :comment %>
<%= f.text_field :comment, class: 'form-control' %>
ActionController::UrlGenerationError in Tobaccos#show No route matches {:action=>"edit", :controller=>"reviews", :id=>nil, :tobacco_id=>"8"} missing required keys: [:id
You are iterating @reviews
as review
, so
this line
<%= link_to "Edit", edit_tobacco_review_path(@tobacco, @review) %>
should be
<%= link_to "Edit", edit_tobacco_review_path(@tobacco, review) %>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With