I have a User model:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile, dependent: :destroy
after_create :build_profile
end
So when the user registers, there profile is created and they are redirected to the edit_profile_page
class RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
edit_profile_path(current_user)
end
end
In my profile model I'm trying to set some validation
class Profile < ApplicationRecord
belongs_to :user
...
validates :name, presence: true
end
Im also using the friendly_id gem
profile_controller.rb
def set_profile
#profile = Profile.friendly.find(params[:id])
end
The error I'm getting is when I register a new user is:
Couldn't find Profile with 'id'=6
This only happens when I try to apply the validates :name, presence: true, without this my application works fine. I need a way to validate the name after the user is registered, after the profile model is created.
Im also getting the error at this line:
def set_profile
#profile = Profile.friendly.find(params[:id])
end
build_profile in after_create builds a profile but it doesn't persist it. It's not created in the database.
Better might be...
def after_sign_up_path_for(resource)
new_profile_path
end
In your controller
def new
#profile = current_user.build_profile
...
end
def create
#profile = current_user.build_profile
if #profile.update_attributes(profile_params)
...
end
...
end
Related
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?
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.
I'm trying to create a Profile model upon my Users registering for the site. As I have it now the Profile model is being created upon registration with the correct foreign key. My problem lies with trying to update the Profile model after the user has gone through the Devise confirmation steps.
My users are called "artists".
### /artists/registrations_controller.rb ###
class Artists::RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
super
#profile = #artist.build_artist_profile
end
# POST /resource
def create
super
#profile = #artist.create_artist_profile(profile_params)
end
private
def profile_params
params.permit(:biography, :location, :genre, :members, :facebook_url, :twitter_url, :youtube_url, :itunes_url, :amazon_url)
end
end
### /artists/profiles_controller ###
class Artists::ProfilesController < ApplicationController
before_action :authenticate_artist!
before_action :correct_artist
before_action :set_artist
def edit
#profile = ArtistProfile.find_by(params[:artist_id])
end
def update
#profile = ArtistProfile.find_by(params[:artist_id])
if #profile.update_attributes(profile_params)
redirect_to current_artist
else
redirect_to root_url
end
end
private
def set_artist
#artist = current_artist
end
def correct_artist
#artist = current_artist
if #artist != Artist.find(params[:id])
redirect_to artist_path
end
end
def profile_params
params.require(:artist_profile).permit(:biography, :location, :genre, :members, :facebook_url, :twitter_url, :youtube_url, :itunes_url, :amazon_url)
end
end
### /artist.rb ###
class Artist < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable
has_one :artist_profile, dependent: :destroy
### /artist_profile.rb ###
class ArtistProfile < ActiveRecord::Base
belongs_to :artist
validates :artist_id, presence: true
end
I put my own code into the Devise registration controller in the create method. Upon registration the ArtistProfile model is created and populated with blank strings, which is prefect. However, if I try to edit/update the individual artist's profile only the very first artist's profile gets updated.
ie. Artist 1 signs up and profile 2 is created. Artist 1 updates Profiles 1's location to Buffalo via the edit page. Artist 2 signs up and Profile 2 is created. Artist 2 updates Profile 2's location to New York, but Profile 1's location is updated, not Profile 2's.
Is this the way to create a model upon registration, and if so, how do I fix the edit/update methods?
Or is there a better way altogether?
This line of your code is incorrect:
#profile = ArtistProfile.find_by(params[:artist_id])
A fix is to find the artist, then get the profile:
#profile = Artist.find(params[:artist_id]).artist_profile
An optimization:
#artist = Artist.find(params[:artist_id]).includes(:artist_profile)
#profile = #artist.artist_profile
Or, if your controller is receiving the artist profile id, then you can do this fix:
#profile = ArtistProfile.find(params[:artist_profile_id])
I'm new to rails and I tried to make simple authentication with anonymous user. I followed this tutorial and I have this error:
undefined method `find_or_initialize_by_token'
This is my AnonymousUser model:
class AnonymousUser < User
ACCESSIBLE_ATTRS = [:name, :email]
attr_accessible *ACCESSIBLE_ATTRS, :type, :token, as: :registrant
def register(params)
params = params.merge(type: 'User', token: nil)
self.update_attributes(params, as: :registrant)
end
end
This is my User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
:rememberable, :registerable, :trackable, :timeoutable, :validatable,
:token_authenticatable
attr_accessible :email, :password, :password_confirmation, :remember_me
end
And the last one important is my ApplicationController which has this error:
class ApplicationController < ActionController::Base
protect_from_forgery
def authenticate_user!(*args)
current_user.present? || super(*args)
end
def current_user
super || AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
end
private
def anonymous_user_token
session[:user_token] ||= SecureRandom.hex(8)
end
end
Someone told me that if AnonymousUser user inherits from User then AnonymousUser have method called find_or_initialize_by_token, but i don't know how to fix it.
Provided you have latest rails installed, try to refactor:
# in ApplicationController#current_user
AnonymousUser.find_or_initialize_by_token(anonymous_user_token).tap do |user|
user.save(validate: false) if user.new_record?
end
to something like this:
AnonymousUser.safely_find(anonymous_user_token)
and push the find_or_initialize_by_token and save(validate: false) into the model.
I wrote the blog post you referenced, but today, I would use
AnonymousUser.where(anonymous_user_token: anonymous_user_token).first_or_initialize
Dynamic finders have been deprecated AFAIK.
However, #Saurabh Jain is absolutely correct in his suggestion to refactor that block into a nice little push-button class method on the AnonymousUser.
I have 2 models in my application ( Using rails 3.2.5)
1) User(From devise)
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
has_many :profiles
end
2) Profiles.
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :description, :name, :product, :image, :price
mount_uploader :image, ImageUploader
validates_presence_of :name, :product, :image, :price
end
There are many profiles of one user .
GOAL : I want to display only the profiles related to each user , when they login.
By reading rails document we can create a new profile for a user by (Code below), But this gives an error
"undefined method `Profile' for nil:NilClass"
Can somebody help me to define my controller's index,show,new,edit,create,update ,destroy or show me one and i can do it for all.
def new
#profile = #user.Profile.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #profile }
end
end
You are receiving this error because the #user is not initialized and is equal to nil so it has no method named profile, you should be using current_user helper of devise to get the current user #user = current_user.