I'am making a controller test, but I have this error. My model tests passing, but about this I don't know what is going on:
/cook-book/test/controllers/recipes_controller_test.rb:23]: "Recipe.count" didn't change by 1 Expected: 3 Actual: 2
my 'recipes_controller_test.rb':
require 'test_helper'
class RecipesControllerTest < ActionController::TestCase
include Devise::TestHelpers
setup do
#recipe = recipes(:one)
user = User.create!(email: "example2#test.com", password: "password",password_confirmation: "password" )
sign_in user
end
....
test "should create recipe" do
assert_difference('Recipe.count') do
post :create, recipe: { title: #recipe.title, image_file_name: #recipe.image_file_name, ingredients: #recipe.ingredients, description: #recipe.description }
end
assert_redirected_to recipe_path(assigns(:recipe))
end
'recipes.yml':
one:
title: MyString
image_file_name: Myimage
ingredients: MyText
description: MyText
two:
title: MyString
image_file_name: Myimage
ingredients: MyText
description: MyText
and recipe model:
class Recipe < ActiveRecord::Base
belongs_to :category
belongs_to :user
has_many :comments
has_attached_file :image, styles: { medium: "400x400#", small: "250x250#"}
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
validates :title, presence: true, length: { maximum: 30 }
validates :ingredients, presence: true
validates :description, presence: true
validates :image, presence: true
searchkick
end
#Edit
my 'recipe_controller'
Class RecipesController < ApplicationController
before_action :find_recipe, only: [ :show, :edit, :update, :destroy ]
before_action :authenticate_user!, except: [:index, :show]
.....
def create
#recipe = current_user.recipes.build(recipe_params)
if #recipe.save
redirect_to #recipe
else
render 'new'
end
end
private
def find_recipe
#recipe = Recipe.find(params[:id])
end
def recipe_params
params.require(:recipe).permit(:title, :ingredients, :description, :image, :category_id)
end
Thanks!
Related
Trying to test the create action in post_controller. All other controllers' create actions work just fine.
After some debugging, the error seems to be the params. The images passed from the post factory are blank in the controller
post_spec.rb
describe 'POST #create' do
it 'check post creation' do
new_post = build :post, user: user
attrs = new_post.attributes
attrs.store(:images, [ Rack::Test::UploadedFile.new(image_url, 'image/jpg') ])
post posts_path, params: { post: new_post.attributes }
expect(response).to be_success
end
end
post.rb(model)
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
has_many :likes, dependent: :destroy
has_many_attached :images
validates :user_id, presence: true
validates :title, presence: true, length: { minimum: 1, maximum: 1000 }
validates :images, presence: true, limit: { min: 1, max: 10 },
content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/webp']
end
post.rb (factory)
image_url = '/home/dev/Downloads/a1.jpg'
FactoryBot.define do
factory :post do
title { Faker::Lorem.sentence }
images { Rack::Test::UploadedFile.new(image_url, 'image/jpg') }
user
end
end
post_controller.rb
def create
#post = Post.new(post_params)
if #post.save
redirect_to post_url(#post), notice: 'Post was successfully created.'
else
render :new, status: :unprocessable_entity
end
end
def post_params
params.require(:post).permit(:title, :user_id, images: [])
end
When check for errors on #post here' the output
['Images cannot be blank']
new_post in post_spec
#<Post id: nil, title: "Sequi excepturi quam quos.", user_id: 307, created_at: nil, updated_at: nil>
new_post.attributes in post_spec
{"id"=>nil, "title"=>"Sequi excepturi quam quos.", "user_id"=>307, "created_at"=>nil, "updated_at"=>nil}
The problem is in your
post_controller.rb
def post_params
params.require(:post).permit(:title, :user_id, images: [])
end
you are requiring an array of images, but in test you pass single instance of image.
Either edit your params.require in controller or update your factory (post) file, what suits better.
So now if you change your factory code to
post.rb (factory)
FactoryBot.define do
factory :post do
title { Faker::Lorem.sentence }
images { [Rack::Test::UploadedFile.new('/home/dev/Downloads/a1.jpg', 'image/jpg')] }
user
end
end
You will have your images filled.
I am working on a pinterest clone and I am having some trouble when i try to create a new pin. I get "NoMethodError - undefined method pins' for nil:NilClass: app/controllers/api/pins_controller.rb:19:in create'"
I am not sure what else to try. I dont know why it doesnt have access to pins. Any suggestions???
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: 'static_pages#root'
namespace :api, defaults: { format: :json } do
resources :users, only: [:show,:new, :create, :index]
resource :session, only: [:new, :create, :destroy, :show]
resources :pins, only: [:create, :show, :index, :edit, :destroy]
resources :boards, only: [:create, :show, :edit, :destroy]
end
end
user.rb
class User < ApplicationRecord
attr_reader :password
validates :username, presence: true, uniqueness: true
validates :password_digest, :session_token, presence: true
validates :password, length: { minimum: 6 }, allow_nil: true
after_initialize :ensure_session_token
has_many :pins,
foreign_key: :author_id,
class_name: :Pin
has_many :boards,
foreign_key: :author_id,
class_name: :Board
has_many :pins_in_boards,
through: :boards,
source: :boards_pins
def self.find_by_credentials(username, password)
user = User.find_by(username: username)
return nil unless user
user.is_password?(password) ? user : nil
end
def password=(password)
#password = password
self.password_digest = BCrypt::Password.create(password)
end
def is_password?(password)
BCrypt::Password.new(self.password_digest).is_password?(password)
end
def ensure_session_token
self.session_token ||= SecureRandom.urlsafe_base64
end
def reset_session_token!
self.session_token = SecureRandom.urlsafe_base64
self.save
self.session_token
end
end
users_controller.rb
class Api::UsersController < ApplicationController
def show
#user = User.find_by(username: params[:id])
if #user
render :show
else
render json: #user.errors.full_messages, status: 404
end
end
def new
#user = User.new
render :new
end
def index
#users =User.all
render :index
end
def create
#user = User.new(user_params)
if #user.save
sign_in(#user)
render "api/users/show"
else
render json: #user.errors.full_messages, status: 422
end
end
private
def user_params
params.require(:user).permit(:password, :username)
end
end
pins_controller.rb
class Api::PinsController < ApplicationController
def index
#pins = user.pins
end
def new
#pin = Pin.new(user_id: current_user.id)
render :new
end
def show
#pin = Pin.find(params[:id])
render :show
end
def create
#pin = current_user.pins.new(pin_params)
if #pin.save
render :show
else
render json: #pin.errors.full_messages, status: 422
end
end
def edit
#pin = Pin.find(params[:id])
unless #pin.author_id == current_user.id
render "api/pins/show"
else
render :edit
end
end
def destroy
pin = current_user.pins.find(params[:id])
pin.destroy
end
private
def pin_params
params.require(:pin).permit(
:title,
:description,
:url,
:author_id,
:photo
)
end
def user
#user ||= User.find(params[:user_id])
end
def pin
#pin ||= current_user.pins.find(params[:id])
end
end
pin.rb
class Pin < ApplicationRecord
validates :title, :description, :author_id, presence: true
belongs_to :user
belongs_to :board
has_many :boards
has_one_attached :photo
has_many :users,
through: :boards,
source: :author
end
creat_pin_form_container.jsx
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import PinForm from './pin_form';
import { createPin } from '../../actions/pins_actions';
import { openModalForm, closeModalForm } from '../../actions/modal_form_actions';
const mapStateToProps = state => ({
pin: {
title: '',
description: '',
photoFile: null
},
formType: 'New Pin'
});
const mapDispatchToProps = dispatch => ({
action: pin => dispatch(createPin(pin)),
closeModalForm: () => dispatch(closeModalForm())
});
export default connect(mapStateToProps, mapDispatchToProps)(PinForm);
pin_form.jsx
import React from 'react';
class PinForm extends React.Component {
constructor(props) {
super(props);
this.state = this.props.pin;
this.handleSubmit = this.handleSubmit.bind(this);
this.handleFile = this.handleFile.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const formData = new FormData();
formData.append('pin[title]', this.state.title);
formData.append('pin[description]', this.state.description);
formData.append('pin[url]', this.state.url);
formData.append('pin[photo]', this.state.photoFile);
this.props.action(formData, this.state.id);
}
update(field) {
return e => this.setState({ [field]: e.currentTarget.value });
}
handleFile(e){
this.setState({ photoFile: e.currentTarget.files[0] })
}
render() {
return (
<div className="pin-form-container">
<form onSubmit={this.handleSubmit}>
This is occurring because the value of current_user is currently set to nil. You need to make sure you have a logged in user.
Im new in ruby on rails and after I included papperclip i get this error if i try to change photo.
If I change create method like in a README.md on paperclip`s github:
def create
#hotel = Hotel.create( hotel_params )
end
private
# Use strong_parameters for attribute whitelisting
# Be sure to update your create() and update() controller methods.
def hotel_params
params.require(:hotel).permit(:name, :photo, :room_description, :price_for_room, :breakfast, :country, :state, :city, :street)
end
I get the same error in Create method. Could you help me? What am I missing here?
Ruby 1.9.3
Rails 4
Paperclip 4.2.0
Error screenshot
hotels_controller.rb
class HotelsController < ApplicationController
before_action :signed_in_user, except: [:index, :show]
def index
#hotels = Hotel.paginate(:page => params[:page], :per_page => 5)
end
def show
#hotel = Hotel.find(params[:id])
#comments = #hotel.comments
end
def new
#hotel = Hotel.new
end
def edit
#hotel = Hotel.find(params[:id])
end
def create
#hotel = current_user.hotels.new(params[:hotel])
if #hotel.save
redirect_to #hotel, notice: "Hotel was successfully created."
else
render "new"
end
end
def update
#hotel = Hotel.find(params[:id])
if #hotel.update_attributes(params[:hotel])
redirect_to #hotel, notice: "Hotel was successfully updated."
else
render "edit"
end
end
def destroy
#hotel = Hotel.find(params[:id])
#hotel.destroy
redirect_to hotels_url
end
end
hotel.rb
class Hotel < ActiveRecord::Base
has_many :comments
belongs_to :user
has_many :ratings
has_many :raters, :through => :ratings, :source => :users
validates :name, presence: true, length: { minimum: 5 }
validates :room_description, presence: true
validates :price_for_room, presence: true, numericality: true
validates_associated :comments
has_attached_file :photo, :styles => { :medium => "500x500>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/
def update_average_rating
#value = 0
self.ratings.each do |rating|
#value = #value + rating.value
end
#total = self.ratings.size
update_attributes(average_rating: #value.to_f / #total.to_f)
end
end
As you are using Rails4, your update action should be like this
def update
#hotel = Hotel.find(params[:id])
if #hotel.update_attributes(hotel_params) #Here
redirect_to #hotel, notice: "Hotel was successfully updated."
else
render "edit"
end
end
I've been developing a web app in Rails 4, and used the Michael Hartl tutorial as the backbone for it, but using Devise as well. After building some of it, I went back and changed the Status model to be polymorphic in order to allow users, venues and groups to be able to post a status. I've got a certain way with this so far, but am now stuck. When trying to view a user's profile, I am currently getting this error:
NoMethodError in Users#show
Showing /home/app_name/app/views/users/show.html.erb where line #6 raised:
undefined method `avatar' for #<ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Status:0xb6859fd8>
Extracted source (around line #6):
<aside class="col-md-4">
<section>
<h1>
<%= image_tag #user.avatar.url(:thumb) %>
<%= #user.name %>
</h1>
</section>
The user definitely has an avatar, and as far as I can work out it seems to be having trouble working out the association through the polynomial relationship. It's on the user#show page, so presumably I shouldn't change "user" to "statusable", I have already tried this anyway, but don't understand where the problem is coming from. The profile shows a feed of statuses at present and an avatar for the user in each.
Any help would be greatly appreciated.
EDIT
Here are my user and status models:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook, :twitter, :google_oauth2]
before_save { self.username = username.downcase }
validates :first_name, presence: true,
length: { maximum: 25 }
validates :last_name, presence: true,
length: { maximum: 25 }
VALID_USERNAME_REGEX = /\A[\w+\-._]+\z/i
validates :username, presence: true,
length: { maximum: 20 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
validates :email, presence: true
validates :password, presence: true
validates :birthday, presence: true
validates :gender, presence: true
validates :postcode, presence: true
validates_format_of :postcode, :with => /\A([A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKS-UW])\s?[0-9][ABD-HJLNP-UW-Z]{2}|(GIR\ 0AA)|(SAN\ TA1)|(BFPO\ (C\/O\ )?[0-9]{1,4})|((ASCN|BBND|[BFS]IQQ|PCRN|STHL|TDCU|TKCA)\ 1ZZ))\z/i, :message => "invalid postcode"
has_attached_file :avatar, :styles => { :medium => "300x300", :thumb => "100x100", :micro => "30x30", :large => "500x500>" }, :default_url => "/images/:style/missing.jpg"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
geocoded_by :address
after_validation :geocode
self.per_page = 20
def address
[town, postcode, country].compact.join(', ')
end
def feed
Status.from_users_favourited_by(self)
end
def self.all_except(user)
where.not(id: user)
end
end
def name
first_name + " " + last_name
end
has_many :statuses, as: :statusable, dependent: :destroy
accepts_nested_attributes_for :statuses
end
class Status < ActiveRecord::Base
before_create :set_latlong
belongs_to :statusable, polymorphic: true
default_scope -> { order('created_at DESC') }
validates :content, presence: true, length: { maximum: 140 }
validates :statusable_id, presence: true
validates :statusable_type, presence: true
def set_latlong
self.latitude = statusable.latitude
self.longitude = statusable.longitude
end
def self.from_users_favourited_by(user)
favourited_user_ids = "SELECT favourite_id FROM favouriteusers
WHERE favourited_id = :user_id"
where("statusable_id IN (#{favourited_user_ids}) OR statusable_id = :user_id", user_id: user.id)
end
end
Here is the Status controller:
class StatusController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
before_filter :load_statusable
def new
#status = Status.new(status_params)
end
def create
#statusable = load_statusable
#status = #statusable.statuses.build(status_params)
if #status.save
flash[:success] = "Status created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#status.destroy
redirect_to root_url
end
private
def status_params
params.require(:status).permit(:content)
end
def load_statusable
resource, id = request.path.split('/')[1, 2]
resource_name = resource.singularize.classify
if resource_name = "user"
#statusable = current_user
else
#statusable = resource_name.constantize.find(id)
end
end
end
And finally the status schema:
create_table "statuses", force: true do |t|
t.string "content"
t.integer "statusable_id"
t.string "statusable_type"
t.float "latitude"
t.float "longitude"
t.datetime "created_at"
t.datetime "updated_at"
end
I've taken a few bits out to make it easier to read, but hopefully have left in the bits needed.
EDIT
class UsersController < ApplicationController
before_filter :authenticate_user!, only: [:index, :show,:edit,
:update, :destroy, :favourite_users, :favourited_users]
def index
#users = User.all_except(current_user).paginate(page: params[:page]).order('created_at DESC')
end
def show
#user = User.find(params[:id])
#user = #user.statuses.paginate(page: params[:page])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
# Handle a successful update.
else
render 'edit'
end
end
def create
#user = User.create( user_params )
end
def favourite_users
#title = "Favourites"
#user = User.find(params[:id])
#users = #user.favourite_users.paginate(page: params[:page])
render 'show_favourite'
end
def favourited_users
#title = "Listed as a Favourite by"
#user = User.find(params[:id])
#users = #user.favourited_users.paginate(page: params[:page])
render 'show_favourite'
end
Well, it sure looks like #user does not contain a User but rather a ActiveRecord::AssociationRelation::ActiveRecord_AssociationRelation_Status. No wonder it doesn't have an avatar method! Check your controller code to see what #user is actually set to. If you can't make sense of what's going on, post the controller here. The User model and schema will probably be needed, too.
I have following associations and the related controller, in my form I am adding every field as it should be. But I still get an error Ratings item can't be blank when I try to create an Item. I am using Rails 4.0 . I did searched extensively for this but could not still find what I am doing wrong. Thankyou!
class Item < ActiveRecord::Base
has_many :ratings, dependent: :destroy
accepts_nested_attributes_for :ratings, :allow_destroy => true
validates :name , :length => { minimum: 3 }
validates :category , :length => { minimum: 3 }
end
class Ratings < ActiveRecord::Base
belongs_to :user
belongs_to :item
default_scope -> { order('created_at DESC') }
validates :user_id, :presence => true
validates :item_id, :presence => true
validates_numericality_of :rating, :greater_than_or_equal_to => 0
validates_numericality_of :rating, :less_than_or_equal_to => 5
end
class ItemsController < ApplicationController
before_action :set_item, only: [:show]
before_action :user_signed_in?, only: :create
def create
#item = Item.new
#rating = #item.ratings.build
#rating.comment = params[:item][:ratings_attributes][:comment]
#rating.rating = params[:item][:ratings_attributes][:rating]
#rating.user_id = current_user.id
#item.name = params[:item][:name]
#item.url = params[:item][:url]
#item.full_address = params[:item][:full_address]
#item.city = params[:item][:city]
#item.country = params[:item][:country]
#item.category = params[:item][:category]
respond_to do |format|
if #item.save
#TODO create rating here (First rating of an Item)
flash[:success] = "Welcome to inmyopnion"
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render action: 'show', status: :created, location: #item }
else
format.html { render action: 'new' }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
def new
#item = Item.new
end
def show
end
def destroy
end
private
def set_item
#item = Item.find(params[:id])
end
def item_params
params.require(:item).permit(:name, :url, :full_address, :city, :country, :category, :ratings_attributes => [:rating, :comment])
end
def user_signed_in?
#TODO: should display should sign in to rate an item
redirect_to(root_url) unless signed_in?
end
end
Simplify your controller! Since you are allowing nested_attributes this should be sufficient:
#item = Item.create(params[:item])
The problem might be caused by #rating object not being saved.
I got it working by commenting the below given line in
class Ratings < ActiveRecord::Base
validates :item_id, :presence => true
but my association rspec test fails and saves a Ratings without an item_id.
Rest of the code is similar to what I posted as
#item = Item.create(params[:item])
gives ActiveModel::ForbiddenAttributesError
Alright much playing with the code and docs of nested_attributes finally a working program that validates association too. These are the changes (marked in between ** .... **) listed below
class Item < ActiveRecord::Base
has_many :ratings, dependent: :destroy, **inverse_of: :item**
accepts_nested_attributes_for :ratings, :allow_destroy => true
validates :name , :length => { minimum: 3 }
validates :category , :length => { minimum: 3 }
end
class Ratings < ActiveRecord::Base
belongs_to :user
belongs_to :item, **inverse_of: :ratings**
default_scope -> { order('created_at DESC') }
validates :user_id, :presence => true
validates_presence_of :item
validates_numericality_of :rating, :greater_than_or_equal_to => 0
validates_numericality_of :rating, :less_than_or_equal_to => 5
end
Still not able to create one from #item = Item.create(params[:item]) which still gives an gives
ActiveModel::ForbiddenAttributesError as suggested by #BroiSatse and also the docs of nested_attributes that should not be the case
the problem might be in
class ItemsController < ApplicationController
def item_params
params.require(:item).permit(:name, :url, :full_address, :city, :country, :category, :ratings_attributes => [:rating, :comment])
end
will work on to resolve that too and post an answer if I find a solution.