How can I add 2 arguments to 1 function? - ruby-on-rails

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)

Related

How to use boolean conditions

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

ruby display delete if product= user product

i have a little problem with a display of a "delete button" i would like that only the user who have post the product can see the button delete so i have try to do a methode who compared id :
def user_publis?
#user=current_user
#publication_id = #publication.user.id
#user_id= #user.id
#publication_id = #user_id
end
a méthode who ask if the publication have build by the current_user
def user_publis?
if #publication=current_user.publications.build
content_tag( :span ,class: "btn btn-rounded") do
content_tag( "my delete button")
end
end
but no one are good....
thx for help and sorry for my english ..^^
You could just write something like this in your view:
<% if #publication.user == current_user %>
<span class="btn btn-rounded">
my delete button...
<% end %>
Or: You can add the following method to your Publication:
def published_by?(user)
self.user == user
end
and use it in your view like:
<% if #publication.published_by? current_user %>
<span class="btn btn-rounded">
my delete button...
<% end %>

Get UserID for Current User using Devise/Rails

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

<% if current_user.id == #status.user_id %> when user not signed in

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 to I get the destroy action to work with administrative control in Rails?

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

Resources