I would like to hide or mask example.com/users/$ID/edit to be example.com/profile/edit.
config/routes.rb
resources :users
app/controllers/users_controller.rb
def edit
#user = User.find(params[:id])
end
I've tried adding the route
match '/profile/edit' => 'users#edit', :as => :edit_profile
but, when I visit example.com/profile/edit, the edit method complains about not being able to find the user's ID.
Is there a way I can mask the ID from the browser?
If you're trying to edit the current user's profile you could use the following in your edit action:
def edit
#user = User.find_by_id( params[:id] ) || current_user
end
This will first try to look up the user by the id parameter returning nil if it can't find the user and if the return value is nil it will set #user to the return value of the current_user helper method. This assumes you're using something like Devise which provides the current_user method to get the currently logged in user.
One other note. You should change match in your route to get to specify that only get requests are valid for the edit action.
get 'profile/edit' => 'users#edit' , as: edit_profile
If you're trying to prevent users from editing other people's profiles you need something like the following after you load the user:
redirect_to( root_path ) and return unless #user == current_user
This will keep the current user from editing another user's profile.
If you want to allow logged in user to change it's profile, maybe you'll want to store user's id in the session.
So when user logs in you save it's ID into the session:
session[:user_id] = ...
Then your edit method will look like
def edit
#user = User.find(session[:user_id])
end
If that solution is not what you want, than you maybe will just need to add the ':id' parameter to the match code.
Related
I'm trying to implement a form with the following behavior:
1) Input some semantic data about a user (i.e. username).
2) Do a User.find_by(:username = username).
3) If such a user exists, direct to show page for that user.
4) If such a user does not exist, create a new user with the provided username, then redirect to the show page for that user.
This should be simple but I cannot figure out how to format the form_for helper and my show and create actions in my user_controller to implement this behavior.
I currently have:
form_with :url => 'users/:id', :method => :get do
...
end
because I'm ultimately trying to invoke the "show" method of the controller. However, my form does not take in a user's id as a parameter, and when the user does not yet exist there is no :id parameter to access at the time of the form's submission.
How can I set up my form to redirect to show in each case, while still adhering to the logic explained above?
You can do something like this in your User's Controller create action
def create
usr_name = params[:username]
#user = User.where(username: usr_name).first_or_initialize
if #user.persisted?
redirect_to user_path(#user) # or whatever your user show path is
elsif #user.save
redirect_to user_path(#user)
else
render :new
end
end
You would just need to make sure that you are validating the uniqueness of usernames.
Also, first_or_initialize(and its counterpart first_or_create) can take in a block. So, you can assign other attributes to the new User like this...
User.where(username: usr_name).first_or_initialize do |usr|
usr.some_attribute = some_value
end
you can use find_or_initialize_by(unique_key) in your create method.unique_key can be any key which you are using to identify your user such as email,phone etc.
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
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?
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.
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)
I am new to rails and have a task that asks me to send an invitation for any user to be admin in my magazine here is my piece of code
def invite
inviteUser = { 'user_id' => current_user.id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end
I need to replace current_user.id with something that refers to any user's id which exists in my database to send him an invitation to be admin with me I tried to add #User=Users.All and then pass it as a variable but it got me an error I tried a lot of things but every time I get an error except for adding current_user.id
ps: I am using devise for authentication
You asked a couple things, and it is kind of confusing what you want to do.
Here is how you get all ids of records in a model.
Rails4: User.ids
Rails3: User.all.map(&:id)
Or (not sure if #pluck is in Rails 3 or not)
User.pluck(:id)
If you want to get a random user (you mentioned "any user") you could do.
User.find(User.pluck(:id).sample)
Though I think what you really want to do is to pass the id or some other attribute of a user as a param to the action and send that user an invitation.
Presumably you either have a post or get route for "users#invite" (the action you wrote in your question). You can add a named parameter there or you can pass a url param or if you are using a post route, you could add the param to the post body.
Then in your contoller you can do something like this (I'll use email as an attribute):
def invite
#user = User.find_by(email: params[:user_email])
#Rails 3 like this
# #user = User.find_by_email(params[:user_email])
# now do stuff with user
end
User.all will return you the collection of users. So,
Find the user object to get an id...
Try this code....
def invite
inviteUser = { 'user_id' => User.find_by_email('user#example.com').id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end
You can try
User.last.id
or
User.find_by_email("xyz#test.com").id
or
User.where(email: "xyz#test.com").first.id
Replace xyz#test.com with desired user email address. To get more details on rails active record query interface, please read rails guides http://guides.rubyonrails.org/active_record_querying.html
How can I root to the current user's show view in a Rails app?
I want to do something like
authenticated :user do
root :to => "users#show"
end
but how do I pass the current user's ID into this?
Thanks
I did a before_filter where I check if request.path == root_path and if so I redirect to the path that should be user-specific root. The root_path set in routes.rb is not user-specific root for any user so there is no infinite redirection. Just do flash.keep to make your flash messages survive the redirection.
EDIT:
Reading Q&A and comments, trying to understand what you already has, and what you still need. Did you succeed to setup routing to get show action rendered without the :id in the URL? If so maybe you need something like this in your controller show action:
if params[:id].nil? # if there is no user id in params, show current one
#user = current_user
else # if there is the user id in params just use it,
# maybe get 'authorization failed'
#user = User.find params[:id]
end
The following worked for me.
In routes.rb:
root to: 'users#current_user_home'
In users_controller.rb:
def current_user_home
redirect_to current_user
end
Is it always the 'current' user or any arbitrary user?
If it is the current user, just direct them all to the same page (without specifying the ID) and in the controller action get the current user (from session etc) and pass it through to the view.
Current user's ID should not be in url, that should be store in session. So you don't need pass it to the route.
Edit:
After reading your comment, I think you could define another action like profile for show the current user 's view.
Or at your users/show action, add some code like:
if current_user.is_admin?
#user = User.find params[:id]
else
#user = current_user
end
I'd like to create a rails route for editing a user's profile.
Instead of having to use /users/:id/edit, I'd like to have a url like /edit_profile
Is it possible to create a dynamic route that turns /edit_profile into /users/{user's id}/edit, or should I do thing in a controller or?
You might want to create a separate controller for this task but you could also continue using users_controller and just check whether there is a params[:id] set:
def edit
if params[:id]
#user = User.find(params[:id])
else
#user = current_user
end
end
But you should note that /users normally routes to the index action and not show if you still have the map.resources :users route. But you could set up a differently called singular route for that:
map.resources :users
map.resource :profile, :controller => "users"
This way /users would list all the users, /users/:id would show any user and /profile would show the show the currently logged in users page. To edit you own profile you would call '/profile/edit'.
Since a route and controller serve two different purposes, you will need both.
For the controller, assuming you're storing the user id in a session, you could just have your edit method do something like:
def edit
#user = User.find(session[:user_id])
end
Then have a route that looks something like:
map.edit_profile "edit_profile", :controller => "users", :action => "edit"
This route would give you a named route called edit_profile_path
Tomas Markauskas's answer could work, but here's the answer to your question from the Rails Guide:
get 'edit_profile', to: 'users#edit'
So, when someone goes to www.yoursite.com/edit_profile, it will route to www.yoursite.com/users/edit.
Then, in your controller you can access the user with
#user = User.find(session[:current_user_id])
Assuming you set that session variable when someone logs in. Also, don't forget to check if they're logged in. This will work if your using Resourceful Routing (the Rails default) or not.
Source: http://guides.rubyonrails.org/routing.html
make the route as
get '/users/:id/edit', to: 'users#edit', as: 'edit_profile'
As explained in this link section 'The hard way' :
http://augustl.com/blog/2009/styling_rails_urls/
The url will be
/users/edit_profile
Because the ID is no longer in the URL, we have to change the code a bit.
class User < ActiveRecord::Base
before_create :create_slug
def to_param
slug
end
def create_slug
self.slug = self.title.parameterize
end
end
When a user is created, the URL friendly version of the title is stored in the database, in the slug column.
For better understanding read the link below
http://blog.teamtreehouse.com/creating-vanity-urls-in-rails
write it in any home controler.
def set_roots
if current_user
redirect_to dashboard_home_index_path
else
redirect_to home_index_path
end
end
in routes.rb file
root :to => 'home#set_roots'
match "/find_roots" => "home#set_roots"