I have a basic rails app with devise set up and a profile model generated with scaffolding. The Profile model is where the user will add detailed information about themselves after they sign up. Everything is working fine except for one issue: after the user creates a profile, the new profile is created however it is not linked to that user id. I have generated the migration to add user_id to profile. How can I make the profile that the user creates get saved and linked to the currently signed in user?
here is my current code:
Profiles controller:
class ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :set_profile, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#profiles = Profile.all
respond_with(#profiles)
end
def show
#profile = Profile.find(params[:id])
respond_with(#profile)
end
def new
#profile = Profile.new
respond_with(#profile)
end
def edit
end
def create
#profile = Profile.new(profile_params)
#profile.save
respond_with(#profile)
end
def update
#profile.update(profile_params)
respond_with(#profile)
end
def destroy
#profile.destroy
respond_with(#profile)
end
private
def set_profile
#profile = Profile.find(params[:id])
end
def profile_params
params.require(:profile).permit(:name, :civil, :email, :level, :employment_date, :mobile, :folder, :title, :internal, :nationality, :vacation, :work_email, :experience)
end
end
Profile model:
class Profile < ActiveRecord::Base
belongs_to :user
validates_associated :user
end
User model:
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_one :profile
end
As long as you use devise, it should be as simple as:
class ProfilesController < ApplicationController
def create
#profile = Profile.new(profile_params)
#profile.user_id = current_user.id
#profile.save
respond_with(#profile)
end
end
Devise creates that helper method for you. Check its docs page.
Related
I have a User model. A user can be an employer or a student. So there is an employer model and a student model. They both belong to user. Only employers can view student profiles. So if there is something wrong with the profile, the employer should be able to report the profile. I was thinking of having a "report" button on the profile which only the employers can see. Then when they click on it, the admin (me) gets an email with the url or the id of the student.
Right now, the student profile url looks like www.mywebsite.com/students/john-big. How can the report button be setup so the whole URL or the user-id (John-big) gets emailed to me.
The mailer is set up already because I set it up in a way where I get an email every time a user signs up. I can use the same logic to email myself, but grabbing the ID or url is the problem. What is the best way to do it?
Userinfo controller (userinfo =student):
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy, :log_impression]
before_action :authenticate_user!
def index
end
def show
end
def new
#userinformation = current_user.build_userinfo
end
def create
#userinformation = current_user.build_userinfo(userinfo_params)
if #userinformation.save
redirect_to userinfo_path(#userinformation)
else
render 'new'
end
end
def edit
end
def update
if #userinformation.update(userinfo_params)
redirect_to userinfo_path(#userinformation)
else
render 'edit'
end
end
def destroy
#userinformation.destroy
redirect_to root_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.friendly.find(params[:id])
end
end
Employer controller:
class EmployersController < ApplicationController
before_action :find_employer, only: [:show, :edit, :update, :destroy]
def index
end
def show
end
def new
#employer = current_user.build_employer
end
def create
#employer = current_user.build_employer(employer_params)
if #employer.save
redirect_to userinfos_path
else
render 'new'
end
end
def edit
end
def update
if #employer.update(employer_params)
redirect_to employer_path(#employer)
else
render 'edit'
end
end
def destroy
#employer.destroy
redirect_to root_path
end
private
def employer_params
params.require(:employer).permit(:paid, :name, :company, :position, :number, :email, :emp_img)
end
def find_employer
#employer = Employer.friendly.find(params[:id])
end
end
User model:
class User < ActiveRecord::Base
has_one :userinfo
has_one :employer
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
acts_as_messageable
after_create :welcome_send
def welcome_send
WelcomeMailer.welcome_send(self).deliver_now
end
end
Please let me know if you guys need more information.
I would use request.url() to get the URL of your view (the student profile url).
Try adding this to you view to get a feeling of it:
<%= debug("request.url: #{request.url()}") if Rails.env.development? %>
I hope this helps.
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
I am using Devise for registration. But I want to build a profile for user so that where user can fill their info.
I want a single for profile for user but whenever new_profile_path another profile is created for that user, I want to avoid user to go to new_profile_path or create new profile after 1 profile is created.
here is the code
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_one :profile
has_many :statuses
end
profile.rb
class Profile < ActiveRecord::Base
belongs_to :user
validates_associated :user
end
profiles_controller.erb
class ProfilesController < ApplicationController
before_action :authenticate_user!
before_action :find_profile, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#profiles = Profile.all
end
def new
#profile = Profile.new
end
def create
#profile = Profile.new(profile_params)
#profile.user_id = current_user.id
#profile.save
respond_with(#profile)
end
def show
#profile = Profile.find(params[:id])
end
def edit
end
def update
#profile.update(profile_params)
respond_with(#profile)
end
private
def find_profile
#profile = Profile.find(params[:id])
end
def profile_params
params.require(:profile).permit(:first_name, :last_name, :birth_date,
:gender, :bio, :personal_website, :linkedin_profile, :facebook_profile,
:mobile_no, :telephone_no)
end
end
This is the current code for creating Profile for user. But every time a profile is created for user through new_profile_path. How can I avoid it?
Thanks in advance for giving your time.
One solution is:
# in User model
has_one :profile
before_create :build_profile, unless: :profile
Alternatively:
# in User model
has_one :profile
after_create :create_profile, unless: :profile
The conditional unless: :profile is there so that it doesn't overwrite a profile that was already added before the user was created.
When your using associations, you have to use build instead of new.... In your Profile controller...
def new
#profile = current_user.build_profile
end
def create
#profile = current_user.build_profile(profile_params)
if #profile.save
flash[:success] = "Profile saved"
redirect_to current_user_path
else
flash[:error] = "Error"
render: new
end
end
This will make sure that only one profile is created for each user...
def edit
#profile = current_user.profile.find(params[:id])
end
def update
#profile = current_user.profile.find(params[:id])
if #profile.update_attributes(profile_params)
flash[:success] = "Successfully updated" # Optional
redirect_to user_path
else
flash[:error] = "Error" # Optional
render :edit
end
end
I am not sure that it is even related but since i added devise i am getting a no method error which reads as follows. undefined method `posts' for nil:NilClass
This is specifically directed at the following line of code.
#post = current_user.posts.build
I am rather stuck here as i have checked all the obvious and unless i remove the code so it reads
#post = Post.new
I am otherwise unable to add new posts. I have added the full code below.
Posts Controller
class PostsController < ApplicationController
before_action :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all.order("created_at DESC")
end
def show
end
def new
#post = current_user.posts.build
end
def create
#post = current_user.posts.build(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to root_path
end
private
def find_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content)
end
end
Post model`
class Post < ActiveRecord::Base
belongs_to :user
end
User model
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 :posts
end
new html haml
%h1 New Post
= render 'form'
The code looks ok...
But what happens if there is no user signed in?
try add
before_action :authenticate_user!
or ask
user_signed_in?
before you try to access the logged in user.
Need to see your how you have integrated your devise. But yes, maybe your not signed in that's why the nil error.
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])