Rails link with error message and current user - ruby-on-rails

I have hard time coming up with an idea how to implement a link called "Add guide", that requires user to be signed in. To direct to new guide path I need to add "new_user_guide_path(#user) or "new_user_guide_path(current_user)", and adding "current_user" or #user causes an error because of being equal nil - so I don't know how to implement new method in guide controller.
PS: I used devise gem to create user model.
my header partial:
<header class="cf header2">
<h1 class="logo"><%= link_to "E-LEARN", root_path %></h1>
<nav>
<ul>
<% unless user_signed_in? %>
<li><%= link_to "Log In", new_user_session_path %></li>
<% else %>
<li><%= link_to "Dashboard", root_path %></li>
<li><%= link_to "Log Out", destroy_user_session_path, method: :delete %></li>
<li><%= link_to "Settings", edit_user_registration_path %></li>
<li><%= link_to "My Account", current_user %></li>
<% end %>
<% if user_signed_in? %>
<li><%= link_to "Add tutorial", new_user_guide_path(#user) %></li>
<% end %>
</ul>
</nav>
</header>
and routes:
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:show, :index, :new] do
resources :guides
end
authenticated :user do
root to: 'users#dashboard', as: "authenticated_root"
end
root 'welcome#index'
end
Error message:
Started GET "/users/sign_in" for 127.0.0.1 at 2015-11-23 23:25:13 +0100
Processing by Devise::SessionsController#new as HTML
Rendered shared/_header.html.erb (2.2ms)
Rendered devise/sessions/new.html.erb within layouts/application (3.1ms)
Completed 500 Internal Server Error in 7ms (ActiveRecord: 0.0ms)
ActionView::Template::Error (No route matches {:action=>"new", :controller=>"guides", :user_id=>nil} missing required keys: [:user_id]):
10: <li><%= link_to "Settings", edit_user_registration_path %></li>
11: <li><%= link_to "My Account", current_user %></li>
12: <% end %>
13: <li><%= link_to "Add tutorial", new_user_guide_path(current_user) %></li>
14: </ul>
15: </nav>
16: </header>
app/views/shared/_header.html.erb:13:in `_app_views_shared__header_html_erb__869860312033883396_70024564174000'
app/views/devise/sessions/new.html.erb:1:in `_app_views_devise_sessions_new_html_erb___1648951009615067685_70024756409300'
And after I changed to current_user.id:
undefined method `id' for nil:NilClass
So basically current user is nil when there is no logged in user - no big suprise. But is there any way to get around this error thanks to some before_filters or before_action and include link to adding guuide that requires logged in user data without user being actually logged in?

You can try this way
`<% if signed_in? %>
<%= link_to "Profile", profile_path %>
<% if can? :update, #user %>
<%= link_to "Admin", admin_root_path %>
<% end %>
<%= link_to "Logout", destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to "Sign in", new_user_session_path %>
<%= link_to "Join Us", new_user_registration_path %>
<% end %>`
And change your
current_user.id to current_user
This worked for me ,hope it will do same for you :-)

Add "Add tutorial" link in else condition:-
<% if user_signed_in? %>
<li><%= link_to "Dashboard", root_path %></li>
<li><%= link_to "Log Out", destroy_user_session_path, method: :delete %></li>
<li><%= link_to "Settings", edit_user_registration_path %></li>
<li><%= link_to "My Account", current_user %></li>
<li><%= link_to "Add tutorial", new_user_guide_path(current_user) %></li>
<% else %>
<li><%= link_to "Log In", new_user_session_path %></li>
<% end %>
Add before_filter in guide controller:-
before_filter :authenticate_user!

Related

How to use the `link_to_unless_current` helper to work for both current or root path?

I am setting up my navbar link_to's and I'm trying to stop a link being rendered if current_path is the same as link_path or if current path is the same as root path, as root path is defined as that same as the link path, as below:
_navbarhtml.erb
<ul class="nav navbar-nav navbar-right">
<% if user_signed_in? %>
<li><%= link_to_unless_current('My Quotes', quotes_path(current_user)) do %></li>
<% end %>
<li><%= link_to_unless_current('New Quote', new_quote_path) do %></li>
<% end %>
<li><%= link_to('My Account', edit_user_registration_path) %></li>
<li><%= link_to "Sign out", destroy_user_session_path, :method => :delete %></li>
<% else %>
<li><%= link_to('Sign in', new_user_session_path) %></li>
<li><%= link_to('Sign up', new_user_registration_path) %></li>
<% end %>
</li>
routes.rb
root 'quotes#new'
Any neat suggestions as to how to nicely write this?
You can try current_page?. Create a helper method like so:
def link_to_unless_current(text, url, options={})
if current_page?(url)
# do something else? maybe create a text which does not have a link?
else
link_to text, url, options
end
end
Now, view will be like:
<%= link_to_unless_current('My Quotes', quotes_path(current_user)) %>
Feel free to change the name of helper method.
Thanks Surya, this is the way i got it to work in the end:
application_helper.rb
def link_to_unless_current_or_root(text, url)
if current_page?(url)
elsif current_page?(root_path)
else
link_to text, url
end
end
_navbar.html.erb
<li><%= link_to_unless_current_or_root('New Quote', new_quote_path) %></li>

Linking to basket/cart in ruby on rails

I have a menu in my header that has a show basket and a login button, each work when the code is placed in separately but not when both lines are in the file.
I'm using devise for the users.
Is there a better way to link to the current basket?
<li><%= link_to basket_path(#basket.id) do %>
<%= image_tag "/assets/viewBasket.png" %>
</li>
<% end %>
<% if signed_in? %>
<li><%= link_to edit_user_registration_path do%>
<%= image_tag"/assets/my_account.png" %></a></li>
<% end %>
<li><%= link_to destroy_user_session_path do%>
<%= image_tag"/assets/logout.png" %></li>
<%end%>
<% else %>
<li><%= link_to new_user_session_path do%>
<%= image_tag"/assets/loginRegisterBtn.png" %></li>
<% end%>
<% end %>
If I run on its own this works but not with the code after.
<li><%= link_to basket_path(#basket.id) do %>
<%= image_tag "/assets/viewBasket.png" %></li>
<% end %>
I think its to do with the way the current basket is set with the session id in the current_basket model.
module CurrentBasket
private
def set_basket
#basket = Basket.find(session[:basket_id])
rescue ActiveRecord::RecordNotFound
#basket = Basket.create
session[:basket_id] = #basket.id
end
end
The closing of <li> must be after the end of the link, like this:
<li>
<%= link_to basket_path(#basket.id) do %>
<%= image_tag "/assets/viewBasket.png" %>
<% end %>
</li>
I used the answer above which helped with one issue, however, I found that I had defined only the shop and index page. Removing this and it now works.
include CurrentBasket
before_action :set_basket, only: [:index, :shop]

Where should I set the current_user so I don't get a missing key error?

My question assumes a specific answer but it may not but accurate.
I've created a route:
get 'users/:id/groups/' => 'users#groups', as: "my_groups"
but when I go to access this path, conditionally, in a view, i get an exception:
ActionController::UrlGenerationError at /
No route matches {:controller=>"users", :action=>"groups"} missing required keys: [:id]
Here is the partial with the offending line:
<% if user_signed_in? %>
<li id="groups-menu" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Groups <b class="caret"></b>
</a>
<ul class="dropdown-menu">
#offending line:
<li><%= link_to 'My Groups', my_groups_path %></li>
<li><%= link_to 'Create a Group', new_group_path %></li>
</ul>
</li>
<li><%= link_to 'Logout', destroy_user_session_path, :method=>'delete' %></li>
<% else %>
<li><%= link_to 'Login', new_user_session_path %></li>
<% end %>
<% if user_signed_in? %>
<li><%= link_to 'Edit account', edit_user_registration_path %></li>
<% end %>
<% if user_signed_in? %>
<% if current_user.has_role? :admin %>
<li><%= link_to 'Admin', users_path %></li>
<% end %>
<% end %>
it seems that there is no current_user set, perhaps?
It's unclear how this could break if the user_signed_in? method is working.
You need to pass in the :id parameter to the url helper function
<li><%= link_to 'My Groups', my_groups_path(current_user) %></li>

Need a simple syntax when using multiple devise user models for the NAV bar, complex conditional

I'm having trouble with coming up with a simple way to write Ruby conditional for this build case. I have 3 devise user models and based on which user logs in I only want the nag bar to show the correct user class. The idea is to have basically 3 blocks of if else statements which uses the devise user_signed_in? helper as you can see below:
<nav class="top-bar">
<section class="top-bar-section">
<ul class="left">
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Admin Login Page", admin_path %></li>
<li><%= link_to "Company Login Page", company_path %></li>
</ul>
<ul class="right">
<% if user_signed_in? %>
<li><%= link_to "Edit Profile", edit_user_registration_path %></li>
<li><%= link_to "Logout", destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "Login", new_user_session_path %></li>
<% if admin_signed_in? %>
<li><%= link_to "Edit Profile", edit_admin_registration_path %></li>
<li><%= link_to "Logout", destroy_admin_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "Login", new_admin_session_path %></li>
<% if company_user_signed_in? %>
<li><%= link_to "Edit Profile", edit_company_user_registration_path %></li>
<li><%= link_to "Logout", destroy_company_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "Login", new_company_user_session_path %></li>
<% end %>
</ul>
The problem is that it doesn't really work like this so the question is twofold. First, how to simply this conditional syntax? Second, how to get it to work?
You probably want an elsif here, rather than 3 separate blocks. Try something to the effect of:
if user_signed_in?
...
elsif admin_signed_in?
...
elsif company_user_signed_in?
...
elsif params[:action] == 'index'
...
elsif params[:action] == 'admin'
...
else
...
end
or alternatively:
if user_signed_in?
...
elsif admin_signed_in?
...
elsif company_user_signed_in?
...
elsif params[:action] == 'index'
...
elsif params[:action] == 'admin'
...
elsif params[:action] == 'company_user'
...
else
# handle any other case where none of above conditions are met, e.g. params[:action] == 'foobar'
end
I was able to find a solution for my problem. I will post the solution in the hopes that it will help someone else out later if/when they're looking to solve the same problem. This is for Rails 4 btw.
First, you need to put the following in the applications_controller.rb file.
def after_sign_in_path_for(resource)
case resource
when User then '/'
when Admin then '/admin'
when CompanyUser then '/company'
end
end
Then, refactor the original question views code to this.
<ul class="right">
<% if user_signed_in? %>
<li><%= link_to "Edit Profile", edit_user_registration_path %></li>
<li><%= link_to "Logout", destroy_user_session_path, method: :delete %></li>
<% elsif admin_signed_in? %>
<li><%= link_to "Edit Profile", edit_admin_registration_path %></li>
<li><%= link_to "Logout", destroy_admin_session_path, method: :delete %></li>
<% elsif company_user_signed_in? %>
<li><%= link_to "Edit Profile", edit_company_user_registration_path %></li>
<li><%= link_to "Logout", destroy_company_user_session_path, method: :delete %></li>
<% else %>
<% if params[:action] == 'index' %>
<li><%= link_to "User Login", new_user_session_path %></li>
<% elsif params[:action] == 'admin' %>
<li><%= link_to "Admin Login", new_admin_session_path %></li>
<% else params[:action] == 'company_user' %>
<li><%= link_to "Company Login", new_company_user_session_path %></li>
<% end %>
<% end %>
</ul>
Hope this helps.

Add Show User Link to Navbar Devise

In a class, I'm built a Pintrest style app, and I recently set up a show action for my users. The link works fine on the individual pins, but when I try to add the users#show link to the Navbar called "Profile" it does not navigate anywhere. The Profile link should navigate to users#show, but the URL is showing for Profile is my pins#index which is my root route. Here are the links in my Navbar under _header.html.erb.
<div class="nav-collapse collapse">
<ul class="nav pull-right">
<% if user_signed_in? %>
<li><%= link_to "Add Trip", new_pin_path %></li>
<li><%= link_to "About", about_path %></li>
<li><%= link_to "Profile", #user %></li>
<li><%= link_to "Logout", destroy_user_session_path, method: :delete %></li>
<% else %>
<li><%= link_to "About", about_path%></li>
<li><%= link_to "Login", new_user_session_path %></li>
<% end %>
</ul>
</div>
Here is my users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#pins = #user.pins.page(params[:page]).per_page(20)
end
end
But the show user link on the pins in _pin.html.erb which is rendered in my pins#index works fine.
<div class="box">
<p class= "description">
<%= pin.description %>
</p>
<%= link_to (image_tag pin.image(:medium)), pin %>
<p class= "author">
<strong>
Posted by <%= link_to pin.user.name, pin.user %>
</strong>
</p>
</div>
Lastly, if I copy the same link that is in _pin.html.erb <%= link_to pin.user.name, pin.user %> to the Navbar, I get undefined local variable or methodpin' for #<#:0x00000100c82520>`.
Here is my routes.rb incase that helps.
devise_for :users
match 'users/:id' => 'users#show', as: :user
You need to use current_user instead of #user, since #user will be nil in most cases (except on your users#show page.
It might also be a good idea to create a /profile route that always loads the current user.

Resources