I have a Users resource and I want to display the "edit" link in the show.html.erb files only when that user is logged in. See screenshots.
Here is a list of users. Notice in the top right that Roger Sterling is logged in.
But if I click on Don Draper, the show.html.erb file displays the "Edit" button. I only want that to appear for Roger Sterling, in this case.
I'm using Devise for authentication. Any ideas on how to accomplish this? Let me know if you need to see any available code.
You can check current_user and user is shown, if they are the same, the link 'Edit' will display. You can define a helper method like this:
def correct_user?(user)
user == current_user
end
In your show action of UsersController will have:
def show
#user = User.find(params[:id])
...
end
and in your view, you can check:
<% if correct_user?(#user) %>
<%= link_to 'Edit', #user %>
<% end %>
Ha. Ok I got it.
Here is the loop in the show.html.erb file:
<% if (#user.name == current_user.name) %>
<%= link_to 'Edit', edit_user_registration_path(#user) %>
<% end %>
And the helper method:
def correct_user
user == current_user
end
Thanks for the push in the right direction!
Related
I'd like to display an "Add to Favourites" button to users that are not logged in so that they can see that logged in users can add posts (in this case) to their favourites.
Here's the current code:
routes.rb
resources :users do
resources :favourites
end
resources :favourites, only: [:create, :destroy]
posts_helper.rb (I'll move this application_helper once I get it working)
PostsHelper
def new_favourite
if signed_in?
return current_user.favourites.build
else
return Favourite.new
end
end
end
show.html.erb
<%= render :partial => 'shared/favourites/favourite_form', :locals => { :object => #post } %>
_favourite_form.html.erb
<% if signed_in? && current_user.favourited?(object) %>
<%= render partial: 'shared/favourites/unfavourite', locals: { object: object } %>
<% else %>
<%= render partial: 'shared/favourites/favourite', locals: { object: object } %>
<% end %>
_favourite.html.erb
<%= form_for(new_favourite, remote: signed_in?) do |f| %>
<div>
<%= f.hidden_field :object_id, :value => object.id %>
<%= f.hidden_field :object_type, :value => object.class.name.demodulize %>
</div>
<%= button_tag(:type => 'submit', :id => 'add_favourite') do %>
Add to Favourites
<% end %>
<% end %>
I want it to not do an ajax call (ie submit the add favourite form using a page reload) if the user is not signed in so that it will see the user is trying to access a protected page, will redirect them to login and upon success [when it redirects them back to where they were originally trying to go] it will add the favourite.
Can someone advise what I would need to change to make this possible.
EDIT:
Code updated to reflect current state.
After signing in it redirects back to No route matches [GET] "/favourites" because favourites are a nested resource under users.
EDIT 2:
The redirect works pretty much the same as in Rails Tutorial:
Redirect user to sign in page (signed_in_user):
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-correct_user_before_filter
Store location to redirect user back to:
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-friendly_forwarding_code
http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code-friendly_session_create
The only difference is that on my signin page I use a facebook omniauth link for the user to login but the redirection after logging in still works as expected.
Use a helper method instead of current_user.favourites.build?
<%= form_for(new_favourite, remote: true) do |f| %>
Helper:
PostsHelper
def new_favourite
if signed_in?
return current_user.favourites.build
else
return Favourite.new
end
end
end
I'm going back to write a basic app with projects that have tasks. In my show view of a project I want to list the tasks and also include a form. When I wire this all up I get 310 Redirect loop. It's been a while since I've written anything from scratch so would appreciate some help looking at my code.
controller code:
def show
#project = Project.find(params[:id])
#task = #project.tasks.new(params[:task])
if #task.save
redirect_to #project, :notice => "Task added"
else
render action: :show
end
end
view code:
<%= #project.project_name %>
<%= form_for(#task) do |m| %>
<%= m.label :Task %>
<%= m.text_field :task_name %>
<%= m.button :submit %>
<% end %>
<% #project.tasks.each do |t| %>
<%= t.task_name %>
<% end %>
project.rb
has_many :tasks
task.rb
belongs_to :project
You are redirecting to #project, which is interpreted as meaning, redirect to the show page for #product. But you are calling redirect from the show page, hence the redirect loop:
request routed to show page
find project
task instantiated
task saved
redirect to show (loop back to 2)
Normally you don't create records in show, you do it in create. Any reason you're doing it this way?
I have tried to get this working, looked at multiple tutorials, questions on here tried different things for about a week now and I can't get the view to work correctly.
I have teams of users. A team has_many users and a user belongs_to a team (one team at a time). I know the association works because I got it working using the console (with some help there). I'm not sure how to get it working in the view. Below is the code, please let me know if more is needed.
What am I missing?
_join_team_button
<%= form_for(#user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Team Show Page
<%= render 'shared/join_team_button %>
Teams Controller
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
Users Controller
def show
#user = User.find(params[:id])
#teams = #user.team
end
I tried to put a complete demonstration of what you are looking for. Let me know if it fits for you.
#FILE: models/team.rb
class Team < AR::Base
has_many :users
end
#FILE: models/user.rb
class User < AR::Base
belongs_to :team
end
#FILE: config/routes.rb
#Here you are defining "users" as a nested resource of "teams"
resources :teams do
resources :users do
member do
put :join
end
end
end
#if you run "rake routes" it will show you the following line along with others
join_team_user PUT /teams/:team_id/users/:id/join(.:format) users#join
#FILE: controllers/team_controller.rb
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
#FILE: views/teams/show.html.erb
<% if(#user) %>
<%= form_for #user, :url => join_team_user_path(#team, #user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
#You dont really need a form for this. You can simply use `link_to` like below
<%= link_to 'Join', join_team_user_path(#team, #user), method: :put %>
#FILE: controllers/users_controller.rb
def join
# params[:id] => is the user_id
#user = User.find(params[:id])
# params[:team_id] => is the team_id
#team = Team.find(params[:team_id])
# Now make the relationship between user and team here.
#user.update_attribute(:team, #team)
end
Update:Based on your comment
Q: Do I create a new user's resource and nest that or do I nest the already establishes user's resource?
Ans: Based on your requirements any resource can be defined both independently or nestedly. But yes you can control that which method will be available in which way. Like in your case, you can allow only join method when your user is nested under team resource.
resources :users, :only=>:join do
member do
put :join
end
end
resource :users
run rake routes with and without :only=>:join option and see differences in available routes.
Q: Will that affect other things?
Ans: If you strictly define your routes following above example, it should not affect other things. You should confirm all the available routes to your application by rake routes.
Q: Should I put my current routes.rb file up there?
Ans: Assuming your current routes.rb will be modified in the above way. Could I answer the question?
Q: Confused about the comments controller?
Ans: Im extreamely sorry. Yes it must be users_controller.rb as the rake routes command is showing. Result of copy and paste from my own example code :P
Q: what should I put there? the build method
Ans: In your case both the user and team is already exists in your database. All you need to do is just setup a relationship. So you can just use update_attribute option. Ive changed the join method. Please check. But yes if want to create new entries you might need build methods.
Sorry for the late reply :)
I figured it out. Still not perfect, but it gets the association working. The team, and the user were already created, I just needed to establish the association, so the build method would not have worked. Here's what I have:
View:
<%= form_for(#user) do |f| %>
<%= f.hidden_field :team_id, :value => #team.id %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Teams Controller:
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = User.find(params[:id]) if signed_in?
end
I am trying to make it so that people who dont have account/are not signed in can see the list of users and all the users posts..
in my users_controller.rb I have
class UsersController < ApplicationController
before_filter :signed_in_user,
only: [:index, :edit, :update, :destroy]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
def index
#users = User.paginate(page: params[:page])
end
def show
#user = User.find(params[:id])
#microposts = #user.microposts.paginate(page: params[:page])
end
I am guessing that the before_filter :signed_in_user is what makes it so only signed in users can access the user list/see user profiles. How can I change this without getting an error?
currently, when I remove the :index portion on line 3, I get the following error.
undefined method `admin?' for nil:NilClass
This is in line 4 of /app/views/users/_user.html.erb
<li>
2: <%= gravatar_for user, size: 52 %>
3: <%= link_to user.name, user %>
4: <% if current_user.admin? && !current_user?(user) %>
5: | <%= link_to "delete", user, method: :delete, confirm: "You sure?" %>
6: <% end %>
7: </li>
I'm assuming your have something like root :to => 'users#index' in your routes.rb file.
Common solutions for 'signed in / not signed in' behavior involves conditionally redirecting based on authentication states, or rendering various partials depending on state.
Under index, your #users instance variable will always contain paginated User models, regardless of state. However, we have no way of knowing what signed_in_user does. If you search for def signed_in_user in your code, you can see what it does. That may reveal something about how the app handles the state of authentication--or also how to proceed if that is what you are building out.
Update
So it looks like you are not populating the current_user object. This is typically a method that will return an object.
If you are using Devise, you may have to do some additional configuration for it in order to make that current_user helper method available to your view.
The nil error is resulting from the fact that current_user returns nil, or simply doesn't exist. So it's essentially trying nil.admin? and causing the Error to be raised.
Maybe the logic you are looking for is,
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.present? && current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete, confirm: "You sure?" %>
<% end %>
You can also investigate the value of current_user from the Rails debugger console. You can add a debugger statement in your controller, and then play around. Also, you can use the Rails console (run rails console from the command line) and play around there too.
Update 2
so why is it that there are no problems populating the current_user
object when I include :index. Why would removing that (see question
above) cause current_user to become depopulated
We can't know what is in the signed_in_user method to investigate further.
However, I have a hunch that current_user == nil is true because you haven't logged in at all.
Im working on a rails app where a user has the ability to upload photos. When a user uploads their photos it will appear on their profile. Everything works great besides when there is no photos created then I am unable to view the user profile page because of the photo being nil.
here is my show method in the users_controller.rb
def show
#user = User.find_by_id(:id)
#photo = #user.photos.find(params[:id])
end
Here is my show.html.erb
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
How can I bypass this error?
The code for your action seems wrong...
It should be this:
def show
#user = User.find(params[:id])
##photo = #user.photos.find(params[:id])
end
I commented out the third line on purpose, because I'm not sure what it is you want to do there, yet.
The #user variable needs to be defined using params[:id], given that this is the show action for the UsersController, so the id for the user will be passed through as params[:id].
But then you go and use this to find the photo for the user, which is what confuses me... the Photo record's id attribute is probably not going to be the same as the User record's id attribute.
So what is it?
You can replace the code in your show.html.erb with this:
<% if #user.photos %>
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
<% end %>
The problem is, when the user doesn't have any photos, #user.photos returns nil so you have to check for that first.