I rather clumsily replaced my own auth system (based on Michael Hartl's tutorial) with the Devise gem today.
I've got most things working again but have a lot of errors relating to use of current_user.
This, for instance, doesn't work any more:
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
I previously had current_user defined in a sessions helper as follows:
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
I've done away with that, thinking that devise provided the same functionality but that doesn't seem to be the case. In almost all of the situations where I was previously using current_user I now get undefined methodcurrent_user?'`. I'm hoping there is something global I can do to make the old usages work?
Any pointers much appreciated. I've had by far my worst day of rails in the six months I've been using it.
EDIT: The comments explain that I no longer have current_user? defined. I've tried adding the following to my users_controller but it doesn't seem to have worked:
def current_user?(user)
user == current_user
end
You deleted your current_user?(user) method with sessions_helper. Now Devise do all the necessary for you, but Devise has only current_user method, no current_user?(user).
You can define it by yourself in any helper, methods from all of them works in any view and any controller.
In fact, if you have many conditions, where you need to check if user is admin, and user isn't a current_user. You can make a separate helper for it. But, as I remember from Michael Hartl's tutorial, there is not many such blocks (:
Something like:
def not_admin?(user)
current_user.admin? && !current_user?(user)
end
So, you can refactor you view:
<% if not_admin?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
Also you can make it more clear with:
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } if not_admin?(user) %>
Related
So I'm obviously confused with boolean flow because I run into a problem each time. NOTE: I am teaching myself to program, you are all my only hope in learning! I am trying to define a method that checks if a user is an admin, so that I can display certain objects in views to ONLY admins simple enough...or not, for some reason it's not recognizing that I'm an admin (when I truly am, I've checked!). With this all being said, I am a newb so go easy on me!
helpers/sessions_helper is used by both my User and Blogpost models:
def current_user #determines if user is logged out or is the current user of the session/cookie of profile
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(cookies[:remember_token])
log_in user
#current_user = user
end
end
end
def current_user?(user)
user == current_user
end
def is_an_admin
if current_user && current_user.admin?
end
end
<div class="col-xs-12">
<h1><%= #blogpost.title %></h1>
<p><%= #blogpost.content %></p>
<% if is_an_admin %>
<%= link_to "Return to blog", blogposts_path %>
<%= link_to "Edit Post", edit_blogpost_path, class: 'btn btn-primary' %> |
<%= link_to "Delete Post", blogpost_path(#blogpost),
method: :delete, data: {confirm: "Are you sure?"}, class: 'btn btn-danger' %>
<% else %>
<%= link_to "Return to blog", blogposts_path %>
<% end %>
</div>
I'm unsure if maybe I have the method in the wrong place? I have tried placing it inside my applications controller and my user controller to no avail. I must be missing something.
Your sintax got messed up, but I think you're always returning nil on the is_an_admin method:
def is_an_admin
if current_user && current_user.admin?
end
end
It does nothing if the condition is true so it's always returning nil
Change it to something like:
def is_an_admin?
current_user and current_user.admin? # or shorter: current_user.try('admin?')
end
I'm new in Rails, I'm doing tutorial by Hartl but I want to add sometimes something special from me to the code. I'm doing microposts right now and I want to add "delete" function to delete micropost, but I want this function to be visible only for admin and for user who made this micropost. Now I don't know how to do that, because when I want to setup <% if current_user(micropost.user) && user.admin %> I get an error wrong number of arguments (given 1, expected 0).
In session_helper.rb I have function def current_user not def current_user(micropost.user) I know that but can I add somehow this micropost.user and get this done? Bellow all code:
app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
<% if current_user(micropost.user) && user.admin %>
<%= link_to "delete", micropost, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>
app/helpers/session_helper.html.erb
def current_user
if (user_id = session[:user_id])
#current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token])
log_in user
#current_user = user
end
end
end
You should simply be checking if current_user == micropost.user. There is no reason to add an argument to current_user, and doing so would make the purpose of that method much less obvious. The method current_user(something) in no way implies an equality check between the current user and the argument, and violates a pretty common Rails practice of defining a method called current_user to return the currently authenticated user.
If you want to define an additional method that checks whether the given user is the current user, you should use current_user?(user). It would be used like this...
<% if current_user?(micropost.user) && user.admin %>
and defined like this:
def current_user?(user)
current_user == user
end
meagar is correct, you should not add parameters to that method. But to allow for parameters all you would have to do is change the def line to something like that, then just reference the user argument where you want to call it, again bad idea but your are an adult.
def current_user(user)
So I, a rails newbie, am currently trying to get the User ID from the current Devise session, and I am having a bit of trouble.
I have this in my controller now:
def index
#currentUser = current_user.id
end
And I want to make a simple if statement to show/hide fields in my form.
<% if #currentUser === #product.user_id %>
<%= link_to "Back", products_path %>
<%= link_to "Edit", edit_product_path(#product) %>
<%= link_to "Delete", product_path(#product), method: :delete, data: { confirm: "Are you sure?"} %>
<% else %>
<span></span>
<% end %>
I have a feeling my syntax in defining my currentUser variable is bad, but I have no idea how to fix this. There were a few similar questions on Stack, but none of them really applied to me or helped me.
Thanks in advance!
I see a few problems here
def index
#currentUser = current_user.id
end
Other than what #HolyMoly already commented, you should use underscore and not camelcase, if current_user is nil here, .id will fail on it, resulting in an exception.
Second, you are checking "ability" by comparing values of ids, I would change your code to do this
<% if allow_product_delete?(#product) %>
In a helper
def allow_product_delete?(product)
return false unless current_user
#product.user_id == current_user.id
end
if you are using devise current_user exists in controller and views, you don't need to define it as an instance variable, it's already defined as a controller method on all actions (by default). so by calling current_user in your views you are done.
If a user is not logged in, current_user will be nil, you always have to prepare for this and protect against it.
Last, I would look into ability gems (cancan or cancancan), those provide a very nice DSL for dealing with what you were trying here.
Have you set it up to actually be able to user current_user ?
in your code you have :
#currentUser = current_user.id
But where was current_user defined? I haven't used Devise but with sessions you could define the value of current_user with a helper method (you may be able to also do it right there in the sessions_controller #create method), like this:
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
then throughout your app you could use current_user.id or current_user.name or whatever you needed.
So while sessions is not Devise, I hope this helps .
First of all, ruby like undescored_rather_than camelCased style.
Secondly, you need two equal signs instead of three. #currentUser == #product.user_id should work
At third, you don't need to compare integer ids, you can compare models, something like that:
<% if current_user == #product.user %>
<%= link_to "Back", products_path %>
<%= link_to "Edit", edit_product_path(#product) %>
<%= link_to "Delete", product_path(#product), method: :delete, data: { confirm: "Are you sure?"} %>
<% end %>
Please note that I omitted the # in current_user method, because current_user is helper for devise, else I removed unnecessary <% else %> (in my opinion)
You should use current_user for this. You can do it everywhere in project. No needs to define variable #currentUser or etc.
You can compare like models
if current_user == #product.user
that is the equivalent to
if current_user.id == #product.user.id
In some cases you can use
if current_user.id == #product.user_id
This prevent extra sql query to load user model
If you are using Devise for authorization and you need control access for actions you should see (maybe use) gem https://github.com/CanCanCommunity/cancancan
https://github.com/airbnb/ruby will help you to stay in tune ;)
Comparing IDs is not the best practice for Rails. If you have previously set up the associations correctly, then you don't need to make a comparison between IDs. For example:
User
has_many :group_events
GroupEvent
belongs_to :user
In this scenario, instead of comparing IDs, you can directly compare with association:
Bad
#group_event.user_id == current_user.id
Good
#group_event.user == current_user
I am going through Michael Hartl's book, "Ruby on Rails Tutorial Learn Web Development with Rails". In the section where he explains how to get administrative access to delete users, I can't seem to get this to work. The delete link won't show up on the web app, and I am mystified as to why this is occurring. This is my unfactored code below, which sits in the directory of: app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "Are you sure?" } %>
<% end %>
</li>
<% end %>
</ul>
<%= will_paginate %>
The methods of current_user.admin? && !current_user?(user) are methods located in: app/helpers/sessions_helper.rb
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user = current_user
end
I've been stuck on this problem for quite a while and have tried many different things to solve the problem, and none of them have worked. I'm running Rails on Windows 7 using the Rubymine IDE. The tutorial was done on a Mac OS X operating system, and I'm thinking maybe the problem might be associated with my setup.
Also are there known issues with tests failing using the Windows cmd when running RSpec versus running it on Mac OS X?
Any help would be much appreciated.
Thank you.
I just figured out what was wrong!
This method was written incorrectly
def current_user?(user)
user = current_user
end
The correct method to get the corresponding code above to work is this:
def current_user?(user)
user == current_user
end
Thank you for all your input!
Make sure in your controller you're calling the destroy action in your controller. Your code looks fine thus far and I'm assuming you're not using cancan for authorization.
In view file
<% if current_user.admin? && !current_user?(user) %>
<%= link_to "delete", user, method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
Controller
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_path }
format.json { head :no_content }
end
end
First post here on SO. I am relatively new to Ruby on Rails and I have been reading through Michael Hartl's book, "Ruby on Rails Tutorial - Learn by Example". However, I have the following problems when running my application that I would be gracious to get solved.
1) When trying to run my application in 'production' mode, I have updated the file 'config/environments.rb' as follows:
# force Rails into production mode when
# you don't control web/app server and can't set it the proper way
ENV['RAILS_ENV'] ||= 'production'
However, when I run the application, I can still see the debugger facility present from the file 'app/views/layouts/application.html.erb'
<!-- Debug applies only to 'development' environment -->
<%= debug(params) if Rails.env.development? -%>
<!-- as determined by "if Rails.env.development?" -->
This leads me to believe that I am still running the application in development mode.
2) For those that have already asked questions about the signin_path problem, I still cannot see a solution that fixes it for me. I am able to sign up users, then automatically redirect them to their profile space. However, the navigation menu does not change accordingly:
<nav class="round">
<ul>
<li><%= link_to "Home", root_path -%></li>
<li><%= link_to "Support", support_path -%></li>
<% if signed_in? %>
<li><%= link_to "Users", users_path -%></li>
<li><%= link_to "Profile", current_user -%></li>
<li><%= link_to "Settings", edit_user_path(current_user) -%></li>
<li><%= link_to "Sign out", signout_path, :method => :delete -%></li>
<% else %>
<li><%= link_to "Sign in", signin_path -%></li>
<% end %>
Here is the code from the 'app/helpers/sessions_helper.rb' file:
def current_user # GET current_user
#current_user ||= user_from_remember_token
end
def signed_in?
!self.current_user.nil?
end
.
.
.
private
def user_from_remember_token
User.authenticate_with_salt(*remember_token)
end
def remember_token
cookies.signed[:remember_token] || [nil, nil]
end
Any help with this is most welcome. I am currently trying to host my application Heroku, but not getting the support I need unfortunately.
Cheers.
check the link if the question is related to heroku server . And if you want to run on local , rails s -p3001 -e production may work
It seems like your signed_in? helper returns not what you want. So at first debug what signed_in? returns like this:
<%= signed_in? %>
or you can raise error with signed_in? as a message.
Also it seems like you forget current_user setter method, which should be called after session is created. You need to have three methods like these:
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
def user_signed_in?
!!current_user
end
def current_user=(user)
#current_user = user
session[:user_id] = if #current_user ? current_user.id : nil
end
I recommend you to move this methods to ApplicationController as protected methods.
And one last advice:
!self.current_user.nil?
looks really bad. Try to avoid using bang!, this should work for you:
self.current_user