Rails - "Comment.count" didn't change by 1 - ruby-on-rails

This question's been solved. Check the bottom line.
Nowadays, I'm building my movie review website on Ruby on Rails but stuck with the Comment.count error. Already checked and tried a lot of options, but any solutions didn't work. Actually, my website works well, but still this test says the error, and I don't understand what is the problem and why it happens. Could you help me to fix this error? Thank you.
error code
test_comment_interface#CommentsInterfaceTest (3.43s)
"Comment.count" didn't change by 1.
Expected: 39
Actual: 38
test/integration/comments_interface_test.rb:19:in `block in <class:CommentsInterfaceTest>'
comments_interface_test
require 'test_helper'
class CommentsInterfaceTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
end
test "comment interface" do
log_in_as(#user)
get root_path
assert_select 'div.pagination'
assert_no_difference 'Comment.count' do
post comments_path, params: { comment: { content: "" } }
end
assert_select 'div#error_explanation'
content = "This comment really ties the room together"
assert_difference 'Comment.count', 1 do #<-----------------------error point
post comments_path, params: { comment: { content: content } }
end
assert_redirected_to root_url
follow_redirect!
assert_match content, response.body
assert_select 'a', text: 'delete'
first_comment = #user.comments.paginate(page: 1).first
assert_difference 'Comment.count', -1 do
delete comment_path(first_comment)
end
get user_path(users(:archer))
assert_select 'a', text: 'delete', count: 0
end
end
comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :movie, optional: true, primary_key: "id"
has_many :favorites, dependent: :destroy
default_scope -> { order(created_at: :desc) }
validates :user_id, presence: true
validates :movie_id, presence: true
validates :content, presence: true, length: { maximum: 250}
end
comments_controller
class CommentsController < ApplicationController
include HTTParty
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#comment = current_user.comments.build(comment_params)
comment_count = Comment.where(movie_id: params[:id]).where(user_id: current_user.id).count
if #comment.valid?
if comment_count < 1
#comment.save
flash[:success] = "Comment created!"
redirect_to root_url
else
flash[:success] = "Can't post a comment twice on the same movie"
redirect_to request.referrer || root_url
end
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#comment.destroy
flash[:success] = "Comment deleted"
redirect_to request.referrer || root_url
end
def edit
#movie_info = Movie.details(params[:movie_id])
#comment = Comment.find(params[:id])
if Movie.exists?(#movie_info["id"])
#movie_db = Movie.find(#movie_info["id"])
#comments = #movie_db.comments.paginate(page: params[:page])
end
end
def update
#comment = Comment.find(params[:id])
if #comment.update(comment_params)
redirect_to root_url
else
render :edit
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
def correct_user
#comment = current_user.comments.find_by(id: params[:id])
redirect_to root_url if #comment.nil?
end
end
comments_controller_test
require 'test_helper'
class CommentsControllerTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
#comment = comments(:orange)
end
test "should redirect create when not logged in" do
assert_no_difference 'Comment.count' do
post comments_path, params: { comment: { content: "Lorem ipsum" } }
end
assert_redirected_to login_url
end
test "should redirect destroy when not logged in" do
assert_no_difference 'Comment.count' do
delete comment_path(#comment)
end
assert_redirected_to login_url
end
test "should redirect destroy for wrong comment" do
log_in_as(users(:michael))
comment = comments(:ants)
assert_no_difference 'Comment.count' do
delete comment_path(comment)
end
assert_redirected_to root_url
end
end
comments.yml
orange:
content: "I just ate an orange!"
created_at: <%= 10.minutes.ago %>
user: michael
movie: harry
tau_manifesto:
content: "Check out the #tauday site by #mhartl: http://tauday.com"
created_at: <%= 3.years.ago %>
user: michael
movie: harry
cat_video:
content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
created_at: <%= 2.hours.ago %>
user: michael
movie: harry
most_recent:
content: "Writing a short test"
created_at: <%= Time.zone.now.to_s(:db) %>
user: michael
movie: harry
<% 30.times do |n| %>
comment_<%= n %>:
content: <%= Faker::Lorem.sentence(5) %>
created_at: <%= 42.days.ago %>
user: michael
movie: harry
<% end %>
ants:
content: "Oh, is that what you want? Because that's how you get ants!"
created_at: <%= 2.years.ago %>
user: archer
movie: harry
zone:
content: "Danger zone!"
created_at: <%= 3.days.ago %>
user: archer
movie: harry
tone:
content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
created_at: <%= 10.minutes.ago %>
user: lana
movie: harry
van:
content: "Dude, this van's, like, rolling probable cause."
created_at: <%= 4.hours.ago %>
user: lana
movie: harry
From the comments below, I fixed some codes like this. Finally it worked, and the problem was solved.
comments_interface_test
def setup
#user = users(:michael)
#movie = movies(:harry) #add
end
assert_difference 'Comment.count', 1 do
post comments_path, params: { comment: { content: content, movie_id: #movie.id } } #fixed
end
comments_controller
private
def comment_params
params.require(:comment).permit(:content, :movie_id) #fixed
end

By looking at your Comment model it looks like a validation error. You have the following validations on the model but on the test, you didn't specify movie_id.
comment.rb
validates :user_id, presence: true
validates :movie_id, presence: true
Instead it should be something like the following params: { id: movie_id, comment: { content: content } }.

Related

Why does my rspec test fail?

I have problem with my "POST create" action. Test passed successfully, when attributes are valid, but when they are invalid, player is also saved. It's strange because, only :invalid_player, can be saved with invalid attributes. If I change for example, wins to -1 or "string", player with attributes :invalid_player is saved. But if I change attributes for :player, like wins = -1, validators prevent player, from being saved.
Console output with error message:
Failures:
1) PlayersController user is signed in POST create with invalid attributes does not save the new player
Failure/Error:
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
expected #count not to have changed, but did change from 1 to 2
# ./spec/controllers/players_controller_spec.rb:111:in `block (5 levels) in <top (required)>'
This is my Player model:
class Player < ActiveRecord::Base
belongs_to :user
belongs_to :tournament
validates :wins, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :loses, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :draws, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
end
Factory file for players:
FactoryGirl.define do
factory :player do
wins 0
loses 0
draws 0
end
factory :invalid_player, parent: :player do
wins -1
loses 0
draws 0
end
end
Spec test:
context "user is signed in" do
before do
#tournament = create(:tournament)
#player = create(:player)
#user = create(:user)
#request.env["devise.mapping"] = Devise.mappings[:user]
sign_in(#user)
controller.stub(:current_user).and_return(#user)
end
describe "GET new" do
end
describe "GET index" do
it "renders the :index view" do
get :index, tournament_id: #tournament
expect(response).to render_template :index
end
end
describe "GET show" do
it "renders the :show view" do
get :show, { id: #player, tournament_id: #tournament }
expect(response).to render_template :show
end
end
describe "POST create" do
context "with valid attributes" do
it "creates a new player" do
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:player) }
}.to change(Player,:count).by(1)
end
it "redirects to the tournament" do
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:player) }
expect(response).to redirect_to #tournament
end
end
context "with invalid attributes" do
it "does not save the new player" do
expect{
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
}.to_not change(Player, :count)
end
it 're-renders the new method' do
post :create, { tournament_id: #tournament, player: FactoryGirl.attributes_for(:invalid_player) }
response.should render_template :new
end
end
end
end
Controller:
class PlayersController < ApplicationController
before_action :set_tournament
before_action :set_admin, only: [:edit, :update, :destroy]
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :destroy]
def index
#players = #tournament.players.all
end
def show
#player = Player.find(params[:id])
end
def new
#player = #tournament.players.new
end
def create
if current_user.player.nil? == false
flash[:error] = "You're already in tournament."
redirect_to tournaments_url
else
#player = #tournament.players.new
#player.user_id = current_user.id
if #player.save
redirect_to #tournament
else
render 'new'
end
end
end
def edit
if current_user == #admin
#player = #tournament.players.find(params[:id])
else
redirect_to tournaments_url
end
end
def update
if current_user == #admin
#player = #tournament.players.find(params[:id])
if #player.update_attributes(game_params)
flash[:success] = "Player was updated successful"
redirect_to #tournament
end
else
redirect_to tournaments_url
end
end
def destroy
#player = Player.find(params[:id])
flash[:success] = "Player deleted"
redirect_to #tournament
end
private
def set_tournament
#tournament = Tournament.find(params[:tournament_id])
end
def set_admin
#tournament = Tournament.find(params[:tournament_id])
#admin = #tournament.user
end
end
You are not assigning any attributes to your model in your create method. You need to do the following (I assume it's rails 4):
#player = #tournament.players.new(player_params)
#...
private
def player_params
params.require(:player).permit(:wins, :loses, :draws)
end
Without any assignment you most likely falling back onto database default value of zero, which is valid.

Ruby on Rails: :topic_id=>nil, I'm lost

So I am working on an assignment at the moment, where I am trying to display favorited posts. I currently have the favorited post displayed, but when I click it, it doesn't doesn't redirect me to anywhere.
Here is the code I currently have:
User#show where I am currently trying to display the favorited posts:
<div class="row">
<div class="col-md-8">
<div class="media">
<br />
<% avatar_url = #user.avatar_url(128) %>
<% if avatar_url %>
<div class="media-left">
<%= image_tag avatar_url, class: 'media-object' %>
</div>
<% end %>
<div class="media-body">
<h2 class="media-heading"><%= #user.name %></h2>
<small>
<%= pluralize(#user.posts.count, 'post') %>,
<%= pluralize(#user.comments.count, 'comment') %>
</small>
</div>
</div>
</div>
</div>
<h2>Posts</h2>
<%= posts_exists? %>
<%= render #user.posts %>
<h2>Comments</h2>
<%= comments_exists? %>
<%= render #user.comments %>
<h2>Favorites</h2>
<% #posts.each do |post| %>
<%= render partial: 'votes/voter', locals: { post: post } %>
<%= link_to post.title, topic_post_path(#topic, post) %>
<%= image_tag current_user.avatar_url(48), class: "gravatar" %>
<%= post.comments.count %> Comments
<% end %>
The error is occuring on the following line:
<%= link_to post.title, topic_post_path(#topic, post) %>
Here is the output from the error:
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"posts", :id=>"54", :topic_id=>nil} missing required keys: [:topic_id]):
29: <h2>Favorites</h2>
30: <% #posts.each do |post| %>
31: <%= render partial: 'votes/voter', locals: { post: post } %>
32: <%= link_to post.title, topic_post_path(#topic, post) %>
33: <%= image_tag current_user.avatar_url(48), class: "gravatar" %>
34: <%= post.comments.count %> Comments
35: <% end %>
app/views/users/show.html.erb:32:in `block in _app_views_users_show_html_erb__1919900632491741904_70127642538380'
app/views/users/show.html.erb:30:in `_app_views_users_show_html_erb__1919900632491741904_70127642538380'
Obviously Topid.id is nil, but I can't figure out why. I'm going to provide you with everything I think you could need? I know this is probably a simple nooby issue, but I've been stuck on it for nearly an entire day already.
Here is my User#Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new
#user.name = params[:user][:name]
#user.email = params[:user][:email]
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][:password_confirmation]
if #user.save
flash[:notice] = "Welcome to Bloccit #{#user.name}!"
create_session(#user)
redirect_to root_path
else
flash[:error] = "There was an error creating your account. Please try again."
render :new
end
end
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
end
end
Here is my Post#Controller:
class PostsController < ApplicationController
before_action :require_sign_in, except: :show
before_action :authorize_user, except: [:show, :new, :create]
def show
#post = Post.find(params[:id])
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
end
def create
#topic = Topic.find(params[:topic_id])
#post = #topic.posts.build(post_params)
#post.user = current_user
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was saved."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post.assign_attributes(post_params)
if #post.save
#post.labels = Label.update_labels(params[:post][:labels])
flash[:notice] = "Post was updated."
redirect_to [#post.topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :edit
end
end
def destroy
#post = Post.find(params[:id])
if #post.destroy
flash[:notice] = "\"#{#post.title}\" was deleted successfully."
redirect_to #post.topic
else
flash[:error] = "There was an error deleting the post."
render :show
end
end
private
def post_params
params.require(:post).permit(:title, :body)
end
def authorize_user
post = Post.find(params[:id])
unless current_user == post.user || current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to [post.topic, post]
end
end
end
Here is my Topics#Controller:
class TopicsController < ApplicationController
before_action :require_sign_in, except: [:index, :show]
before_action :authorize_user, except: [:index, :show]
def index
#topics = Topic.all
end
def show
#topic = Topic.find(params[:id])
end
def new
#topic = Topic.new
end
def create
#topic = Topic.new(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
redirect_to #topic, notice: "Topic was saved successfully."
else
flash[:error] = "Error creating topic. Please try again."
render :new
end
end
def edit
#topic = Topic.find(params[:id])
end
def update
#topic = Topic.find(params[:id])
#topic.assign_attributes(topic_params)
if #topic.save
#topic.labels = Label.update_labels(params[:topic][:labels])
flash[:notice] = "Topic was updated."
redirect_to #topic
else
flash[:error] = "Error saving topic. Please try again."
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
if #topic.destroy
flash[:notice] = "\"#{#topic.name}\" was deleted successfully."
redirect_to action: :index
else
flash[:error] = "There was an error deleting the topic."
render :show
end
end
private
def topic_params
params.require(:topic).permit(:name, :description, :public)
end
def authorize_user
unless current_user.admin?
flash[:error] = "You must be an admin to do that."
redirect_to topics_path
end
end
end
Here is my User Model:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :favorites, dependent: :destroy
before_save { self.email = email.downcase }
before_save { self.role ||= :member }
EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, length: { minimum: 1, maximum: 100 }, presence: true
validates :password, presence: true, length: { minimum: 6 }, if: "password_digest.nil?"
validates :password, length: { minimum: 6 }, allow_blank: true
validates :email,
presence: true,
uniqueness: { case_sensitive: false },
length: { minimum: 3, maximum: 100 },
format: { with: EMAIL_REGEX }
has_secure_password
enum role: [:member, :admin]
def favorite_for(post)
favorites.where(post_id: post.id).first
end
def avatar_url(size)
gravatar_id = Digest::MD5::hexdigest(self.email).downcase
"http://gravatar.com/avatar/#{gravatar_id}.png?s=#{size}"
end
end
Here is my Topic Model:
class Topic < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
end
Here is my Post Model:
class Post < ActiveRecord::Base
belongs_to :topic
belongs_to :user
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
has_many :labelings, as: :labelable
has_many :labels, through: :labelings
has_many :favorites, dependent: :destroy
default_scope { order('rank DESC') }
scope :visible_to, -> (user) { user ? all : joins(:topic).where('topics.public' => true) }
validates :title, length: { minimum: 5 }, presence: true
validates :body, length: { minimum: 20 }, presence: true
validates :topic, presence: true
validates :user, presence: true
def up_votes
votes.where(value: 1).count
end
def down_votes
votes.where(value: -1).count
end
def points
votes.sum(:value)
end
def update_rank
age_in_days = (created_at - Time.new(1970,1,1)) / 1.day.seconds
new_rank = points + age_in_days
update_attribute(:rank, new_rank)
end
end
Any insight anyone could provide, I would be extremely grateful for. If you have the time to explain where I went wrong as well, that would be even more helpful.
User#show where I am currently trying to display the favorited posts
But you're not setting #topic in your User#show action. That's why it's nil.
def show
#user = User.find(params[:id])
#posts = #user.posts.visible_to(current_user)
#posts = Post.joins(:favorites).where('favorites.user_id = ?', #user.id)
#favorites = current_user.favorites
# your #topic object is not in here?
end
Since a post belongs_to a topic you could do something like this:
<%= link_to post.title, topic_post_path(post.topic, post) %>

Rspec param is missing or the value is empty: user

Hello i'm testing the Update action the User Controller using Rspec.
I get this error
1) UsersController POST #update user updated
Failure/Error: patch :update, {id: user.id }, { user_id: user.id }, user: user_params
ActionController::ParameterMissing:
param is missing or the value is empty: user
# /Users/joseph/.rvm/gems/ruby-2.1.2/gems/actionpack-4.2.0/lib/action_controller/metal/strong_parameters.rb:249:in `require'
# ./app/controllers/users_controller.rb:60:in `user_params'
# ./app/controllers/users_controller.rb:39:in `update'
Weird thing is i used a binding.pry to test whats going on. There is a user and there are user_params. So i don't understand why i receive the above error.
Please see below for the user and user params.
From: /Users/joseph/Documents/Safsy/Website/Safsy/Safsy/spec/controllers/users_controller_spec.rb # line 76 :
71: end
72: end
73:
74: describe "POST #update" do
75: it "user updated" do
=> 76: binding.pry
77: patch :update, {id: user.id }, { user_id: user.id }, user: user_params
78: expect(response).to redirect_to(assigns(:user))
79: expect(assigns(:user)).to eq(user)
80: end
81: end
[1] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> patch :update, {id: user.id }, { user_id: user.id }, user: user_params
ActionController::ParameterMissing: param is missing or the value is empty: user
from /Users/joseph/.rvm/gems/ruby-2.1.2/gems/actionpack-4.2.0/lib/action_controller/metal/strong_parameters.rb:249:in `require'
[2] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> user
=> #<User:0x007fd91fe40458
id: 2,
username: "username2",
email: "user2#factory.com",
created_at: Thu, 08 Oct 2015 11:09:54 UTC +00:00,
updated_at: Thu, 08 Oct 2015 11:09:54 UTC +00:00,
password_digest: "$2a$04$YsvGZ05kdqMoa5fhJlkh1Oa9ISN6wuO7TBCT23vVDS.UO1k.vKTA2",
remember_digest: nil,
admin: false,
activation_digest: "$2a$04$GzFp9Otdlo7l1JBPOTeiQu7NUZELLQSIkLZUd7df1h2p4XpqNXLMm",
activated: true,
activated_at: nil,
reset_digest: nil,
>: nil,
reset_sent_at: nil,
avatar_file_name: nil,
avatar_content_type: nil,
avatar_file_size: nil,
avatar_updated_at: nil,
description: "Corporis odio magni repellendus.",
header_image_file_name: nil,
header_image_content_type: nil,
header_image_file_size: nil,
header_image_updated_at: nil>
[3] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)> user_params
=> {:username=>"username512",
:email=>"user463#factory.com",
:password=>"Password123",
:password_confirmation=>"Password123",
:admin=>false,
:description=>"Nihil eligendi ab debitis iure."}
[4] pry(#<RSpec::ExampleGroups::UsersController::POSTUpdate>)>
here is the User controller
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(
:username,
:email,
:password,
:password_confirmation,
:avatar,
:header_image,
:description
)
end
Here is the complete test
require "rails_helper"
RSpec.describe UsersController, type: :controller do
let!(:admin) { create(:user, password: "Password123", admin: true) }
let!(:user) { create(:user, password: "Password456", admin: false) }
let!(:users) do
[admin, user] + 3.times.map { create(:user) }
end
let!(:user_params) { user_params = { username: "username#{rand(1000)}",
email: "user#{rand(1000)}#factory.com",
password: "Password123",
password_confirmation: "Password123",
admin: false,
description: "Nihil eligendi ab debitis iure.",
} }
let!(:category) { create(:category, name: "Shirt") }
let!(:category1) { create(:category, name: "Short") }
describe "GET #index" do
it "admin user renders template and shows users" do
get :index, {}, { user_id: admin.id }
expect(response).to render_template(:index)
expect(response).to have_http_status(:success)
expect(assigns(:users).map(&:id)).to eq users.map(&:id)
end
it "user renders template and shows users" do
get :index, {}, { user_id: user.id }
expect(response).to redirect_to(root_path)
end
it "redirects visitor" do
get :index
expect(response).to redirect_to(root_path)
end
end
describe "GET #show" do
it "user renders template and shows user" do
get :show, id: user.id
expect(response).to render_template(:show)
expect(response).to have_http_status(:success)
expect(assigns(:user)).to eq(user)
end
end
describe "GET #new" do
it "renders template" do
get :new
expect(response).to render_template(:new)
expect(response).to have_http_status(:success)
end
end
describe "POST #create" do
it "user created" do
post :create, user: user_params
expect(assigns(:user)).to be_persisted
end
end
describe "GET #edit" do
it "user edit" do
get :edit, {id: user.id }, { user_id: user.id }
expect(response).to render_template(:edit)
expect(response).to have_http_status(:success)
expect(assigns(:user)).to eq(user)
end
end
describe "POST #update" do
it "user updated" do
patch :update, {id: user.id }, { user_id: user.id }, user: user_params
expect(response).to redirect_to(assigns(:user))
expect(assigns(:user)).to eq(user)
end
end
describe "DELETE #destroy" do
it "user destroy" do
delete :destroy, {id: user.id }, { user_id: user.id }, user: user_params
expect(response).to redirect_to(users_path)
end
end
end
User controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :update, :edit]
before_action :logged_in_user, only: [:edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:destroy, :index]
def index
#users = User.paginate(page: params[:page])
end
def new
#user = User.new
end
def show
#items = #user.items.paginate(page: params[:page])
end
def show_user_items
#user = User.find(current_user)
#items = #user.items.paginate(page: params[:page])
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
end
def update
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_path
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(
:username,
:email,
:password,
:password_confirmation,
:avatar,
:header_image,
:description
)
end
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
Here is my log_in method
def log_in(user)
session[:user_id] = user.id
end
def logged_in?
!current_user.nil?
end
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
Change this:
patch :update, {id: user.id }, { user_id: user.id }, user: user_params
to this:
patch :update, id: user.id, user: user_params, { user_id: user.id }

Rspec and FactoryGirl: stack level too deep error

I'm new to rails and working on embedding associations into my models for my API. However adding the embeds has caused my specs to fire the following error:
Rails: 4.2.3 Ruby:2.2.1 Rspec: 3.3.2 FactoryGirl: 4.5.0
1) Api::V1::ProductsController GET #show returns the information about a reporter on a hash
Failure/Error: get :show, id: #product.id
SystemStackError:
stack level too deep
I think from looking at other answers on stack overflow that there is a problem with how I'm using my factories in my tests.
Here are the models:
product.rb
class User < ActiveRecord::Base
validates :auth_token, uniqueness: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
before_create :generate_authentication_token!
has_many :products, dependent: :destroy
def generate_authentication_token!
begin
self.auth_token = Devise.friendly_token
end while self.class.exists?(auth_token: auth_token)
end
end
user.rb
class Product < ActiveRecord::Base
validates :title, :user_id, presence: true
validates :price, numericality: { greater_than_or_equal_to: 0 },
presence: true
belongs_to :user
end
and the factories:
users.rb
FactoryGirl.define do
factory :user do
email { FFaker::Internet.email }
password "12345678"
password_confirmation "12345678"
end
end
products.rb
FactoryGirl.define do
factory :product do
title { FFaker::Product.product_name }
price { rand() * 100 }
published false
user
end
end
and here is the spec I'm getting all of the errors from.
products_controller_spec.rb
require 'spec_helper'
describe Api::V1::ProductsController do
describe "GET #show" do
before(:each) do
#product = FactoryGirl.create :product
get :show, id: #product.id
end
it "returns the information about a reporter on a hash" do
product_response = json_response[:product]
expect(product_response[:user][:email]).to eql #product.user.email
end
it "has the user as an embeded object" do
product_response = json_response[:product]
expect(product_response[:user][:email]).to eql #product.user.email
end
it { should respond_with 200 }
end
describe "GET #index" do
before(:each) do
4.times { FactoryGirl.create :product }
get :index
end
it "returns 4 records from the database" do
products_response = json_response
expect(products_response[:products]).to have(4).items
end
it "returns the user object into each product" do
products_response = json_response[:products]
products_response.each do |product_response|
expect(product_response[:user]).to be_present
end
end
it { should respond_with 200 }
end
describe "POST #create" do
context "when is succesfully created" do
before(:each) do
user = FactoryGirl.create :user
#product_attributes = FactoryGirl.attributes_for :product
api_authorization_header user.auth_token
post :create, { user_id: user.id, product: #product_attributes }
end
it "renders the json representation for the product record just created" do
product_response = json_response[:product]
expect(product_response[:title]).to eql #product_attributes[:title]
end
it { should respond_with 201 }
end
context "when is not created" do
before(:each) do
user = FactoryGirl.create :user
#invalid_product_attributes = { title: "Smart TV", price: "Twelve dolalrs" }
api_authorization_header user.auth_token
post :create, { user_id: user.id, product: #invalid_product_attributes }
end
it "renders an errors json" do
product_response = json_response
expect(product_response).to have_key(:errors)
end
it "renders the json errors on why the product could not be created" do
product_response = json_response
expect(product_response[:errors][:price]).to include "is not a number"
end
it { should respond_with 422 }
end
end
describe "PUT/PATCH #update" do
before(:each) do
#user = FactoryGirl.create :user
#product = FactoryGirl.create :product, user: #user
api_authorization_header #user.auth_token
end
context "when is successfully updated" do
before(:each) do
patch :update, { user_id: #user.id, id: #product.id,
product: { title: "An expensive TV"} }
end
it "renders the json representation for the updated user" do
product_response = json_response[:product]
expect(product_response[:title]).to eql "An expensive TV"
end
it { should respond_with 200 }
end
context "when is not updated" do
before(:each) do
patch :update, { user_id: #user.id, id: #product.id,
product: { price: "two hundred" } }
end
it "renders an errors json" do
product_response = json_response
expect(product_response).to have_key(:errors)
end
it "renders the json errors on why the user could not be created" do
product_response = json_response
expect(product_response[:errors][:price]).to include "is not a number"
end
it { should respond_with 422 }
end
end
describe "DELETE #destroy" do
before(:each) do
#user = FactoryGirl.create :user
#product = FactoryGirl.create :product, user: #user
api_authorization_header #user.auth_token
delete :destroy, { user_id: #user.id, id: #product.id }
end
it { should respond_with 204 }
end
end
And the Products Controller:
class Api::V1::ProductsController < ApplicationController
before_action :authenticate_with_token!, only: [:create, :update]
respond_to :json
def show
respond_with Product.find(params[:id])
end
def index
respond_with Product.all
end
def create
product = current_user.products.build(product_params)
if product.save
render json: product, status: 201, location: [:api, product]
else
render json: { errors: product.errors }, status: 422
end
end
def update
product = current_user.products.find(params[:id])
if product.update(product_params)
render json: product, status: 200, location: [:api, product]
else
render json: { errors: product.errors }, status: 422
end
end
def destroy
product = current_user.products.find(params[:id])
product.destroy
head 204
end
private
def product_params
params.require(:product).permit(:title, :price, :published)
end
end
user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :email, :created_at, :updated_at, :auth_token
has_many :products
end
EDIT: Adds Products Controller

Rspec controller test not passing validations, but has valid data

I'm trying to write a controller test for my update route using Rspec with factory girl but I can't get my test to pass validations even though I'm pretty sure the data in my factories is valid.
Here are my factories:
FactoryGirl.define do
factory :user do
username { Faker::Internet.user_name(8) }
password 'password'
end
factory :post do
title { Faker::Lorem.sentence }
body { Faker::Lorem.paragraph }
author { Faker::Internet.user_name(8) }
end
end
here is my model:
class Post < ActiveRecord::Base
validates :title, :body, :author, presence: true
end
Here is my test:
require 'rails_helper'
describe PostsController do
let!(:user) { FactoryGirl.create :user }
let!(:post) { FactoryGirl.create :post }
let(:attributes) { FactoryGirl.attributes_for :post }
describe 'PUT #update' do
let(:title) { "A treatise on Malomars." }
it 'updates a field on a blog post' do
put :update, id: post.id, post: {title: title}
expect(post.reload.title).to eq(post.title)
end
end
end
The error I'm getting is:
Failure/Error: put :update, id: post.id, post: {title: title}
ActiveRecord::RecordInvalid:
Validation failed: Body can't be blank
EDIT---
here is the controller:
class PostsController < ApplicationController
def index
#posts = Post.all
end
def new
end
def create
post = Post.new
post.title = params[:title]
post.body = params[:body]
post.author = "#{session[:username].titleize} Force"
redirect_to root_path
post.save!
end
def show
p session[:id]
#post = Post.find(params[:id])
end
def update
post = Post.find(params[:id])
post.title = params[:post][:title]
post.body = params[:post][:body]
post.save!
redirect_to root_path
end
def destroy
post = Post.find(params[:id])
post.destroy
redirect_to root_path
end
end
Strong parameters aside, you're setting post.body to nil since you're not passing a value for the body parameter in your test. When you call save! in your controller, you're getting an error because you have a validation for body being present (i.e. not nil).

Resources