Routing issue in ruby on rails - ruby-on-rails

For user profile I make an action in home controller and I want that when user click on my profile link only shows www.abc.com/profile
For it I do
get '/profile' => 'home#profile'
But now issue is that there is a need to send user id along with that.If I send it in format then url become
www.abc.com/profile.4
I want that url remains '/profile' and Id of user also send

This is because you're setting it as a member route (it expects to pass the id for the controller). You need to replace it with a collection route, if you're going to nest it:
#config/routes.rb
devise_for :users ... do
get :profile, to: "home#profile", on: :collection, as: :profile #-> url.com/users/profile
end
You'd then be able to access the profile as follows:
<%= link_to "Profile", users_profiles_path, if user_signed_in? %>
If you wanted to make it so that you could access profile without nesting, your route would work:
#config/routes.rb
get "profile", to: "home#profile", as: :profile
<%= link_to "Profile", profile_path if user_signed_in? %>
Controller
We have a setup similar to this, let me explain the controller setup...
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
def edit
#user = current_user
end
def update
#user = current_user
...
end
end
This gives us the ability to use the following (we also use devise):
#config/routes.rb
resource :profile, path: "profile", controller: :users, path_names: { edit: "" }, only: [:edit, :update] #-> domain.com/profile

If you want the url to stay /profile then you'll have to rely on your login implementation. I've not used devise myself, but according to the documentation it provides you with a current_user method to use in your controllers. So your HomeController#profile would look something like this:
def profile
#user = current_user
render :profile
end
That way you don't need the client to send the id to you, because (as I understand it) this should be the profile page of the logged in user, which you should already have information about through devise.
Otherwise you need to allow the id to come through the path by defining the route like so:
get '/profile/:id' => "home#profile"

in devise gem they had mentioned current_user model so use
current_user.id
to find the User id so that in your profile action do like this, and pass the user id of current user so that you can easily fetch his details

Related

Ruby on Rails: links redirecting to home page, but would like to gain access without permission

I have links in a users page where I keep getting redirected to home page if I'm not the signed in user.
routes.rb
resources :users, only: [:show] do
resources :interests, only: [:create]
member do
get 'interests'
get 'likes'
get 'followers'
get 'following'
end
end
views/users/show.haml
= link_to user_path do
User
= link_to likes_user_path do
Likes
= link_to followers_user_path do
Followers
= link_to following_user_path do
Following
If I'm viewing my own user page, all links work. But if I'm viewing someone else's page, only the user_path work correctly, but the other links just redirects me to home page as if I can't access it unless I'm the signed in user.
users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def show
#user = User.friendly.find(params[:id])
end
end
I find it odd that I don't even need to have a method for likes, following, and followers in my controller?
Those links are directing to these pages:
views/users/likes.haml
views/users/following.haml
views/users/followers.haml
Fix
I can't access it unless I'm the signed in user
The problem is you're calling before_action :authorize_user! on all the users_controller methods. This triggers the Devise user authentication check, which means that only logged-in users are able to view that page.
What you'll want is to limit the authentication to only the actions you want:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user, except: [:likes, :followers, :following]
end
This will only apply to the users controller -- interests should allow you, unless you're using authenticate_user! on there.
Misc
I find it odd that I don't even need to have a method for likes, following, and followers in my controller?
Rails 4+ has a built-in mechanism to load views regardless of whether the action is present or not.
--
Rails doesn't need index method in controller defined? (Docs):
By default, controllers in Rails automatically render views with names that correspond to valid routes. For example, if you have this code in your BooksController class:
class BooksController < ApplicationController
end
And the following in your routes file:
resources :books
And you have a view file app/views/books/index.html.erb:
<h1>Books are coming soon!</h1>
Rails will automatically render app/views/books/index.html.erb when you navigate to /books and you will see "Books are coming soon!" on your screen.
Notes
There are some fixes to your syntax:
Routes
Your routes can be DRYed up:
#config/routes.rb
resources :users, only: [:show] do
resources :interests, only: [:index, :create] #-> url.com/users/:user_id/interests
%i(likes followers following).each { |link| get link, on: :member #-> url.com/users/:id/likes }
end
Links
You should use the in-line style of link_to if you've only got a single string to output:
#app/views/users/show.haml
= link_to "User", user_path(user) #-> this should have a reference like user_path(user)
= link_to "Likes", likes_user_path(user)
= link_to "Followers", followers_user_path(user)
= link_to "Following", following_user_path(user)
This is because of the code in your user_controller
before_filter :authenticate_user!
This code will be executed for every controller actions and will be redirecting you to login page.Just add exceptions for the methods you want access directly without being login.
For more details on adding exceptions to methods in Rails please find the bellow SO threads.
1.before_filter with exception for current user
2.How to skip a before_filter for Devise's SessionsController?

Rails - Devise - User Profile url with username on

I would like to get user profiles accessible from the URL: root/user/(username)
As of now I have it working with root/user/(id) but i want it to be more user friendly and shareable with the username in the URL.
This is how I currently have it set up
#user_controller.rb
class UserController < ApplicationController
def profile
#user = User.find(params[:id])
end
end
#routes.rb
match 'user/:id' => 'user#profile'
#profile.html.erb
<h1><%= #user.firstname %>'s Profile</h1>
Basically what I'm trying to do is to change out :id for :username. I've created the usernames in the user models from devise so I know that is working. But right now when I try to get usernames in the URL I get Couldn't find User with id=username.
Change your controller
class UserController < ApplicationController
def profile
#user = User.find_by_username(params[:username])
end
end
Then the route
match 'user/:username' => 'user#profile'
Try friendly_id. No need for any hacks in controller or model level.

"Cannot find User without an ID" error after logging in using Devise

I have started building a simple rails app and have used Devise for authentication. I have created a Dashboard page for the users after they login, it's using a users_contoller added below:
class UserController < ApplicationController
before_filter :authenticate_user!
def show
#user = User.find(params[:id])
end
end
I have renamed this user#show to dashboard in routes:
match '/dashboard', to: 'user#show'
I have created a if else statement in the User show html page to see if this works, shown below:
<% if #user.lists.any? %>
Cool you have lists
<% else %>
OK No Lists
<%= #user[:id] %>
<% end %>
Unfortunately this just renders an error when trying to load the page in a browser
Couldn't find User without an ID
Im not sure if this is simply a Devise setting or something more fundamental and apologies in advance if this is avery noob question.
When a user is autenticated using devise the current autenticated user is "stored" in a helper called "current_user".
A quick fix for your problem should be changing the code in your "UserController" to something like this (at the same time mantaning the rest funcionality):
class UserController < ApplicationController
before_filter :authenticate_user!
def show
#user = params[:id].blank? ? current_user : User.find(params[:id])
end
end
Your route:
match '/dashboard', to: 'user#show' doesn't include the id parameter, you need to do as #Immendes suggested and use the current_user helper otherwise change your route to:
match '/dashboard/:id', to: 'user#show' and send the id

Route and controller design for vote/like resource

I have a like model, recording which user liked which record. I used polymorphic association so a user can like many models.
Currently I use nested-resources to handle likes.
POST /items/:item_id/likes
DELETE /items/:item_id/likes/:id
Now for some reasons I want to get rid of the use of like_id by designing a better route. This is because it will be easier to cache a fragment view.
Note that item model is only one of a few models which are likable, and I want to avoid code duplication if possible.
What's a good way to design routes and controllers that will not use like_id but also allows better code reuse in controller?
Possible implementation
I was thinking of routes like this:
POST /items/:item_id/like
DELETE /items/:item_id/like
I won't use nested like resource. Instead I place a like action in items controller. It will determine if the request is a POST or a DELETE and act accordingly. This however doesn't feel DRY.
I don't know about Rails necessarily, but in Zend Framework I would create a front controller plugin to route all requests with methods 'LIKE' and 'UNLIKE' to a particular controller which then deduces which route was requested, and subsequently which resource was requested, and then performs the necessary actions to 'like' or 'unlike' that resource in the name of the requesting user.
Why? Because the user is 'like'-ing or 'unlike'-ing the resource in question, not 'creating a like' or 'deleting a like'. Sure, in the backend, the 'like' is a record in a cache or database that gets created or deleted -- but the semantics of a resource are not necessarily equivalent that of whichever method is used to persist that resource.
What you need is Singular Resources.
routes.rb
resources :items do
resource :like, only: [:create, :destroy]
end
likes_controller.rb
class LikesController < ApplicationController
before_action :load_likeable
def create
#like = Like.where(likeable: #likeable, user: current_user).first_or_create
redirect_back(fallback_location: #likeable)
end
def destroy
#like = Like.find_by(likeable: #likeable, user: current_user).destroy
redirect_back(fallback_location: #likeable)
end
private
def load_likeable
klass = [Recording].detect { |c| params["#{c.name.underscore}_id"] }
#likeable = klass.find(params["#{klass.name.underscore}_id"])
end
end
likes_helper.rb
module LikesHelper
def like_button_for(item)
if item.liked
form_tag recording_like_path(item), method: :delete do
button_tag "UnLike"
end
else
form_tag recording_like_path(item), method: :post do
button_tag "Like"
end
end
end
end
item.liked is method from Item model

Change route with or without login in Rails

Like the title says, i would like to change the route depending on if there is a user logged in or not, similarly to facebook. Is this possible?
You don't change the route, you just add a :before_filter in your controller. There's a few ways to do it, but a simple example is pretend your root points at homeController#main. On top of the controller you have something like
before_filter :check_login, :only => {:main}
And then in your ApplicationController you write a method like
def check_login
if !session[:userid].nil
redirect_to :controller => :users, :action => :profile
end
end
Which will check your session variable for a user and redirect to their profile if it exists, if not, then it will render your main method normally.
More information and examples here.

Resources