Getting error: undefined method `call' for nil:NilClass - ruby-on-rails

I get such an error when try to create a new bound essence.
NoMethodError in AccountsController#create undefined method `call' for nil:NilClass
I have 2 bound models:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
has_one :account, dependent: :destroy
end
class Account < ApplicationRecord
belongs_to :user, optional: true
end
Account controller look like:
class AccountsController < ApplicationController
before_action :authenticate_user!
def new
#user = User.find_by(id: current_user.id)
#account = #user.build_account
end
def create
#user = User.find_by(id: current_user.id)
#account = #user.build_account(account_params)
if #account.save
flash[:success] = 'Account saved successfully'
redirect_to #account
else
render action: "new"
end
private
def account_params
params.require(:account).permit(:gender, :date_birthday, :description, :location, :nationality, :interests, :first_name, :last_name)
end
end
I tried to write #user.account.new(..), but it didn't help. I guess the error can appear because of I have an any errror in routes. But I checked it many times and found nothing.
Why do I get this error? I will be glad for your help!

Related

Couldn't find Suscription without an ID

I have an application with users using devise for authentication, in the user model I have added in the database a column called admin with false value by default. that way I have managed to have access as administrator to certain parts of the application.
I have a subscription model and each user when authenticated gets a free value by default. what I want to achieve is that the admin user in your user list can be able to switch from free to premium. this is the code i have and i can't get it to work.
Users Model:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
#Validaciones
validates :nombre, :apellido, presence: true
devise :database_authenticatable, :validatable, password_length: 8..128
#Relaciones
has_many :patients, dependent: :destroy
has_many :articles, dependent: :destroy
has_one :profile, dependent: :destroy
has_one :suscription, dependent: :destroy
#Creación de perfil
after_create :set_profile
def set_profile
self.profile = Profile.create()
end
#Creación de suscripcion
after_create :set_suscription
def set_suscription
self.suscription = Suscription.create()
end
end
Suscription Model:
class Suscription < ApplicationRecord
belongs_to :user
enum status: {
free: 0,
premium: 1
}
end
Users controllers:
class UsersController < ApplicationController
def index
#pagy, #users = pagy(User.order(created_at: :asc), items:12)
end
def show
#user = User.find(params[:id])
end
end
Suscriptios controller:
class SuscriptionsController < ApplicationController
before_action :set_suscription
def show
end
def edit
end
def update
#suscription = Suscription.find(params[:id]).update_params
redirect_to profile_path
flash[:notice] = "La suscripción ha sido actualizada"
end
private
def set_suscription
#suscription = (current_user.suscription ||= Suscription.create)
end
def suscription_params
params.require(:suscription).permit(:status)
end
end
Route:
#UPDATE PREMIUM
patch "suscriptions", to:"suscriptions#update", as: "user_premium"
View (Link):
<%= link_to 'Update', user_premium_path ,method: :patch %>
This should fix it:
subscriptions_controller.rb
def update
#suscription = Suscription.find(params[:id]).update(subscription_params)
redirect_to profile_path
flash[:notice] = "La suscripción ha sido actualizada"
end
view
<%= link_to 'Update', user_premium_path(id: #subscription.id, status: "premium"), method: :patch %>
One other thing that is not needed, but normally I would see something like this in a controller:
private
def set_suscription
#suscription = Suscription.find(params[:id])
end
which then makes your update method look like this:
def update
#subscription.update(subscription_params)
redirect_to profile_path
flash[:notice] = "La suscripción ha sido actualizada"
end
This is all assuming you are simply trying to update the subscription from free to premium with your link_to. I wouldn't recommend doing anything like this, because what if someone accidentally marks this? They can no longer go back to a free subscription. Maybe have a modal open that is routed to subscription edit with a drop down to select the status would be better?

Rails error : undefined method `product' for #<User:0x00007faaa8c42700> Did you mean? products products=

I am trying to develop a Shopping application which has 3 models namely User(Devise), Product and Batch. I've made an has_many association between User and Product and created a User(signed up in Devise). And then I changed the association into has_and_belongs_to_many and created a migration to create the join table. I've followed this answer https://stackoverflow.com/a/57017241/9110386 to add the Product to current_user. Then I deleted my User account and tried to sign up but it shows an error like this.
NoMethodError in Devise::RegistrationsController#create
undefined method `product' for # Did you mean? products products=
User model:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
has_and_belongs_to_many :products, :dependent => :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates_length_of :product, maximum: 10
end
Product model:
class Product < ApplicationRecord
belongs_to :batch
has_and_belongs_to_many :user
validates :name, presence: true
validates_associated :user
end
Product Controller
class ProductsController < ApplicationController
before_action :authenticate_user!
def index
#products = Product.all
end
def show
#product = Product.find(params[:id])
end
def new
#product = Product.new
end
def edit
end
def create
end
def update
end
def destroy
end
def add_cart
product = Product.find(params[:product_id])
#current_user.products << product
#current_user.products << product unless current_user.products.include?(product)
if current_user.products.include?(product)
redirect_to products_path, notice: "Already in your cart"
else
current_user.products << product
redirect_to products_path, notice: "Added to cart"
end
end
end
What am I doing wrong here. And I also want to remove the Product from the cart by destroying it from the current_user. How to do that?
Thanks in advance.
You have left behind an old validation in your user model.
Delete this line in the app/models/user.rb file
validates_length_of :product, maximum: 10
Your error is flagging the Devise RegistrationsController’s create method. You’ve likely left a reference to user.product in there whereas users have products plural.

Move method from Controller to Model in Rails

I have been told to move a method "Top" from Controller to Model, but when I try to call it, it doesn't work anymore.
I am using Rails 6
This is my Controller:
class UsersController < ApplicationController
before_action :authenticate_user!
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#posts = #user.posts.ordered_by_most_recent
end
def edit
#user = User.find(params[:id])
end
def following
#title = 'Following'
#user = User.find(params[:id])
#users = #user.following.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = 'Followers'
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
def top
#userst = User.joins(:followers).order('COUNT(followings.follower_id) DESC').group('users.id').limit(10)
end
end
and this would be my Model:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, authentication_keys: [:username]
validates :fullname, presence: true, length: { maximum: 20 }
validates :username, presence: true, length: { maximum: 20 }
validates_uniqueness_of :username
has_many :posts
has_many :active_followings, class_name: 'Following',
foreign_key: 'follower_id',
dependent: :destroy
has_many :passive_followings, class_name: 'Following',
foreign_key: 'followed_id',
dependent: :destroy
has_many :following, through: :active_followings, source: :followed
has_many :followers, through: :passive_followings, source: :follower
mount_uploader :photo, FileUploader
mount_uploader :coverimage, FileUploader
# Follows a user.
def follow(other_user)
following << other_user
end
# Unfollows a user.
def unfollow(other_user)
following.delete(other_user)
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
end
All code here makes sense to me, so I only had to create a file called top.html.erb like this to render the Top:
<article class="timeline new-initial">
<h3>Top:</h3>
<ul class="posts">
<%= render #userst %>
</ul>
</article>
Now, to be honest, I am lost, I am not sure how to move this method to the User model in the right way to read it in the view section.
This seems like a job for a scope.
Model:
scope :top, -> { joins(:followers).order('COUNT(followings.follower_id) DESC').group('users.id').limit(10) }
Controller:
def top
#userst = User.top
end

undefined method `current_user' for #<Teacher:0x00000004fcac48>

I am using Devise gem in my Rails project. The reason I use Devise is because I want just logged in user can rate their teachers. Now, I get this error in my ratings_controller.rb although I already added user_id into my ratings and teachers table.
undefined method `current_user' for Teacher:0x00000004fcac48
#rating = #teacher.current_user.ratings.build
Here is my ratings_controller.rb:
class RatingsController < ApplicationController
def new
get_teacher
#rating = #teacher.current_user.ratings.build
end
def create
get_teacher
#rating = #teacher.current_user.ratings.create(rating_params)
if #rating.save
redirect_to school_teacher_path(#teacher.school, #teacher)
else
render 'new'
end
end
def destroy
get_teacher
#rating = #teacher.ratings.find(params[:id])
#rating.destroy
redirect_to school_teacher_path(#teacher.school, #teacher)
end
def get_teacher
#teacher = Teacher.find(params[:teacher_id])
end
private
def rating_params
params.require(:rating).permit(:easiness, :helpfulness, :clarity, :comment,
:teacher_id, :school_id)
end
end
rating.rb:
class Rating < ActiveRecord::Base
belongs_to :teacher
belongs_to :user
end
teacher.rb:
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :ratings, dependent: :destroy
has_many :users
def name
"#{firstName} #{middleName} #{lastName}"
end
def to_s
name
end
end
user.rb:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :ratings
has_many :teachers
end
current_user is a controller helper, it's not a instance method of model.
you can add before_action :authenticate_user! in controller to make sure only logged in user can rate
You can change several code here. Before fixing your code, I suggest you to user before_action to make DRY code.
class RatingsController < ApplicationController
before_action :authenticate_user!
before_action :get_teacher
# your code #
private
def get_teacher
#teacher = Teacher.find(params[:teacher_id])
end
def rating_params
params.require(:rating).permit(:easiness, :helpfulness, :clarity, :comment, :teacher_id, :school_id)
end
end
Then, add before_action :authenticate_user! above before_action :get_teacher so you can get current_user in each method.
Finally, you have to fix your new and create method into this:
def new
#rating = current_user.ratings.build
end
def create
#rating = current_user.ratings.create(rating_params)
if #rating.save
redirect_to school_teacher_path(#teacher.school, #teacher)
else
render 'new'
end
end
You do not need to #teacher.current_user.ratings.create(rating_params) to get teacher_id because you have teacher_id in your rating_params. I hope this help you.
You need to build rating object for user like this:-
#rating = current_user.ratings.build

Rails self-join gives an error

I'm having troubles getting my friending model in Rails 4 working. I set up a friendship controller and modified my User model to use a self-join as follows.
Friendship Model:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User", foreign_key: "friend_id"
validates_presence_of :user_id, :friend_id
end
User Model:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_many :items
has_many :friendships
end
My UserController:
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!
load_and_authorize_resource
def index
authorize! :index, #user, message: 'Not authorized as an administrator.'
#users = User.all
end
def update
authorize! :update, #user, message: 'Not authorized as an administrator.'
if #user.update_attributes(params[:user])
redirect_to users_path, notice: "User updated."
else
redirect_to users_path, alert: "Unable to update user."
end
end
def destroy
authorize! :destroy, #user, message: 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, notice: "User deleted."
else
redirect_to users_path, notice: "Can't delete yourself."
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit( :name, :email, :role_ids, :id, :user_id )
end
end
The relevant portion of my log:
NoMethodError - undefined method friends' for nil:NilClass:
app/views/users/index.html.erb:32:in_app_views_users_index_html_erb__2019584293611114470_70229529361660'
Unless I've missed this completely, I should be able to access a friend as #users.friends but that gives me a NoMethod Error. I've also tried accessing it as #users.friendships but I get the same error.
I have run the migration and restarted my rails server. I don't know what I'm missing but I would sure appreciate a fresh set of eyes. I think it must be something with how I've set up the model.
The models look fine, however in the index method on UsersController you have the following line: #users = User.all. This creates an array of users which means you can't call .friends on it. You need to access each user individually through iteration
#users.each do |user|
user.friends
# ... more code
end
or some other means.

Resources