2

Say for instance I have a posts controller that currently has a method user_posts which shows all of the posts that are associated with the user with the associated id as so:

def user_posts
    @user = User.find(params[:id])
    @posts = @user.posts.all
end

I want the url to be: foo.com/my_posts when the posts have the same ID as my current_user; How would I do this? currently my routes are set up as so:

get 'user/posts/:id', to: 'posts#user_posts', as: 'user/posts'

I know that I could create an entirely new controller action for my_posts but I want to know if there is a way to do it in the config/routes.

If for example I am browsing throughout the site and tap on a link that says "user posts" I would expect to go the the users posts and if that user happens to be me I would like the url to show website.com/my_posts

Dylan L.
  • 1,243
  • 2
  • 16
  • 35

3 Answers3

1

As I know - no. It's possible to create in routes redirect route and check some conditions (example from documantation):

get 'jokes/:number', to: redirect { |params, request|
  path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
  "http://#{request.host_with_port}/#{path}"
}

But it's impossible to check current user in routes. Redirect can be implemented in the controller with two separate actions as mentioned.

Also available a little trick - generate from the beginning 'right' routes if you use html.erb (slim/haml). For current user posts link can be generated not as usual user/posts/:id but /my_posts (it's possible to check current user id without any problems) and define two routes:

get 'user/posts/:id', to: 'posts#user_posts', as: 'user/posts'
get 'my_posts', to: 'posts#user_posts', as: 'my_posts'

In controller check request.path to find user:

user = request.path == '/my_posts' ? current_user : User.find(params[:id])

Hope it helps.

idej
  • 5,034
  • 1
  • 11
  • 14
1

If I understand well, you have a list of users (including the currently connected user) and each has a link 'user posts' to see the user's posts.

You can simply do:

views

In your views, change the user post link according to the user id. As you loop through your users, check if the user's id is the same as the currently logged user. If yes, change the link to the /my_posts route as follow:

<% if user.id == current_user.id %>
  <%= link_to "My posts", my_posts_path %>
<% else %>
  <%= link_to "User posts", user_posts_path(user) %>
<% end %>

routes.rb

Add a my_posts route that points to the same controller method as user/posts.

get 'user/posts/:id', to: 'posts#user_posts', as: 'user/posts'
get 'my_posts', to: 'posts#user_posts', as: 'my_posts'

controller

In your controller method, we need to instantiate the @user to get its posts. If there is no :id in the params (like the /my_posts route), then set the @user to the current_user. If an :id is passed, set the @user by fetching it from the db.

def user_posts
    @user = params[:id].present? ? User.find(params[:id]) : current_user
    @posts = @user.posts.all
end

No need to do checking in the routes.rb file. This is simple and more "Rails" like.

Is this what you are looking for?

Jeremie
  • 2,241
  • 2
  • 17
  • 25
  • Perfect! yes this is exactly what I was looking for. Simple and elegant answer as well. Explain each piece with a little bit more detail and I'll award the bounty. – Dylan L. Apr 03 '17 at 05:19
  • Glad I could help! I edited my answer with detailed explanations. – Jeremie Apr 03 '17 at 06:53
0

I'm guessing you didn't want to use the index method of the posts controller because you were using it to show all posts from all users, but you can still use it. Here's how:

class PostsContoller < ApplicationController
  def index
    @posts = if params[:user_id].present?
               User.find(params[:user_id]).posts
             else
               Post.all
             end
  end
end

Then in your routes file do this:

resources :posts
resources :users do
  resources :posts
end

This allows posts to be a first class resource as well as a nested resource. Now when you go to /posts/ you get all posts, but when going to /users/:user_id/posts you get only posts from the given user.

In your app, when you need to link to all posts from all users, you can do

posts_path

and when you need to link to just a user's posts you can do

user_posts_path(user)

Jimmy Baker
  • 3,215
  • 1
  • 24
  • 26