When a user is looking at a user profile page, if the current user == the user profile I want to show an edit button...
So I have the following in the view:
<% if can? :update, #user %>
<%= link_to 'Edit', edit_user_registration_path %>
<% end %>
And then in CanCan I have the following:
def initialize(user)
.
.
.
can :update, User do |user2|
user2.try(:id) == user.id
end
But this is always equaling yes. not sure why? ideas
I change the CanCan user var to current_user and that did it. I think the two users were confusing each other.
Related
I'm trying to allow users to show the edit button only if the profile belongs to them. Currently, they're only allowed to edit the profile if it belongs to them but I can't seem to hide the button. I have this so far
<% if request.original_url == request.base_url + "current_user.id" %>
<%= link_to "Edit Profile", edit_user_path(current_user), class: "btn btn-primary btn-xs" %>
<% end %>
This is what I'm trying to compare:
request.original_url => localhost:3000/users/random_user
request.base_url + "users/" + current_user.id => localhost:3000/users/current_user
Thanks in advance.
Authorization
To give you some perspective, you'll be looking for something called authorization.
This is different from authentication because it deals with permissions, rather than identifying your identity. I'll get into how this works in a minute.
To solve your problem, here's what you need to do:
<%= link_to "Edit Profile", edit_user_path(current_user), class: "btn btn-primary btn-xs", if user_signed_in? && current_user == #user %>
I'm guessing you're showing this on a user#show action, which can be invoked using the following code:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find params[:id]
end
end
This means that if you have the following routes:
#config/routes.rb
resources :users
you'll have access to #user and current_user. It's important to note that current_user != #user. Although weezing's answer is succinct, it does not validate whether the user is the one which owns the page authorized; just that the user is authenticated
Thus, you have several specifications:
You need to know if the user is actually logged in
You need to make sure your logged-in user has the authorization to edit the profile (IE is it theirs)
I would highly recommend looking into the use of gems such as CanCanCan or Pundit. I'll show you CanCanCan:
#app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
can :edit, Article, id: user.id
end
end
#app/views/users/show.html.erb
<%= link_to "Edit", edit_user_path(#user) if can? :edit, #user %>
There is a great resource here.
This should work (little bit simpler):
<% if current_user %>
<%= link_to "Edit Profile", edit_user_path(current_user), class: "btn btn-primary btn-xs" %>
<% end %>
I am a rookie in Rails. I am using Rails 4 and I could not find how they do this or what it is called.
I got this idea from devise where you can use devise and implement such thing in your application.html.erb file:
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
Where user is the devise model.
However when I try to search for user_signed_in or current_user variable, I cannot find it at all!
So essentially what I want to do is link this user model (which is used for devise) with another model that I created called profile. These models are linked by their ids, and if user has not created a profile, then simply ask user to create his/her profile.
To do that, I've written this to application.html.erb:
<% if user_signed_in? && (current_profile.id != current_user.id)? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
Which does not work as expected because I have not defined current_profile. The error that I am getting is:
undefined local variable or method `current_profile' for #<#<Class:0x000000044d6c60>:0x00000005d64110>
My question is, how do I create a variable named current_profile that would contain the current profile, like current_user that devise does?
The usual setup for this is to add a Profile model with a user_id:integer field.
Define an assocition on the User model
has_one :profile
Then you can access it directly using
current_user.profile
You can do the following:
class User
has_one :profile
# ...
class Profile
belongs_to :user
# ...
module ApplicationHelper # app/helpers/application_helper.rb
def current_profile
#current_profile ||= current_user.try(:profile)
#current_profile
end
# ...
# view
<% if user_signed_in? && current_profile.blank? %>
<%= link_to 'You have not created your profile! Please create your profile first.', update_profile_index_path, :class => 'navbar-link' %>
<% else %>
<%= yield %>
<% end %>
I added an admin boolean column to my user table and toggled my user to yes. I changed the following code so that the "edit" button shows to teh admin for all pins:
<% if current_user == pin.user || current_user.admin? %>
<p>
<%= link_to 'Edit', edit_pin_path(pin) %>
<%= link_to content_tag(:i, "", class:"icon-trash"), pin, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
<% end %>
When I try to edit a pin, I get an error: Couldn't find Pin with id=37-outer [WHERE "pins"."user_id" = 1]
I believe this is because of the pins controller, but I haven't figured out how to correctly change it to allow admins to edit. Here's my controller:
def edit
#pin = current_user.pins.find(params[:id])
end
I have a feeling this is an easy fix that I'm just missing.
you are scoping pins to the current_user which is the reason why you're getting the error. Try changing the code that finds the pin to
klass = Pin
klass = klass.where(user_id: current_user.id) unless current_user.admin?
#pin = klass.find(params[:id])
alternatively, if this is something you'll be using in a lot of places, it may be good to define a class method instead
# app/models/pin.rb
def self.find_for_user(pin_id, user)
user.admin? ? find(pin_id) : user.pins.find(pin_id)
end
# in your controller
#pin = Pin.find_for_user(params[:id], current_user)
Currently, I have in my 'show' view for a question model
<% if current_user.id == #question.user_id %>
<%= link_to 'Edit', edit_question_path(#question) %>
<% else %>
<% end %>
To allow the user that created the question to edit it. This works fine when a user is logged in.
However, if a guest is not logged in. I get this error:
NoMethodError in Questions#show
undefined method `id' for nil:NilClass
It doesn't seem to like this line
<% if current_user.id == #question.user_id %>
Can anyone advise a rewrite to get this to work with guest users too?
Thanks
Why not do something like <% if current_user == #question.user %>? Take out the IDs.
Or if you really want the IDs. something like <% if current_user.present? && current_user.id == #question.user_id %>
In a helper
def current_user?(user)
current_user && current_user == user
end
Then in the view
<% if current_user?(#question.user) %>
You can't have an user.id if the user is not in the database. There is a good screencast about this: http://railscasts.com/episodes/393-guest-user-record?view=asciicast
#BillyChan - for that requirement, i would allow upvoting if someone isn't signed in. No need to create an unsaved user record. I'd probably want to use cookies to stop people multiple-upvoting, but to be honest i'd probably argue with the client that we shouldn't let people upvote without being logged in.
Use this
<% if current_user.present? && current_user.id == #question.user_id %>
How can I set an ability to allow a user to only edit their own profile? The edit link is placed in their own show page like so:
<% if can? :update, User %>
<div class="button">
<%= link_to 'edit my profile', edit_user_path(#user) %>
</div>
<% end %>
The ability currently looks like this:
if user.role == "author"
can :create, Review
can :update, Review do |review|
review.try(:user) == user
end
can :update, User, :id => user.id
end
I have load_and_authorize_resource in the user controller too.
But this doesn't work, the user (with role of author) can still see and use the edit button on all users show pages.
What am I doing wrong here?
Thanks very much for any help its much appreciated!
Should be:
<% if can? :update, #user %>
You need to pass the actual object instance instead of the class.