I am working on a social media site and I am having a problem with routing.
Every user has a profile page like facebook and this is the root I use:
get 'profile(/:id)' => 'profiles#show'
So, when the URL is like this: www.sitename.com/profile/1 it opens up the page belongs to user with id 1. But, I also want users to be able to use their usernames in url without /profile/. So it is gonna be like facebook.
For example: www.sitename.com/handsomeboy69
How can I do this in routing? Because, rails may think that username passed in URL is a page name.
Thank you
I fixed it. This is the route I used:
get ':username' => 'profiles#show'
In the controller I used this statement:
if params.has_key?(:username)
#profile = User.find_by_username(params[:username])
elsif params.has_key?(:id)
#profile = User.find(params[:id])
else
end
else statement at the end is empty, I am gonna use that area to print out error message saying that profile cannot be found.
and most important part is that this routing should be at the end of the file.
Related
In the users controller for my app I have a method for viewing the posts generated by users, but when you go to the index page and click on another user, the page of the currently logged in user shows up but the url is for the user I just clicked onto.
This is the method in my users controller
def feed
#title = "Feed"
#user = User.find(session[:user_id]) # This is the problem
feed = Feed.new(#user)
render 'show_feed'
end
I'm also having trouble understanding the difference between session[:user_id] and params[:id]. If I change session[:user_id] to params[:id] while on the page, of the user I just clicked onto, their posts are then shown, but when I go back to the logged in user's page I get the error "Couldn't find User with 'id'=user_id" in "app/controllers/users_controller.rb:59:in `feed'" So my question is, what do I need to pass into #user = User.find() to get the correctly generated page/s?
Generally if you're clickiing on a link to see some OTHER user, the link has an "id" embedded in it which is passed in the params, so you would do...
#user = User.find(params[:id])
Your link to go back to the logged in user is incorrect, but you haven't shown that link. It should most probably be something like
<%= link_to user_path(session[:user_id]) %>
From the description of your problem you may be doing...
<%= link_to user_path('user_id') %>
... which doesn't make sense... it means literally go to the user record with the id of "user_id"
session is data (usually stored in a cookie) that is persistent from one request to another and that expires at the end of the browser session. A common use is to store the id of the logged in user.
By passing that to User.find you're entirely ignoring the user id that is in the URL. You should be using params[:id] (unless your routes are naming that segment of your url differently)
Your problem when you "go back" is not clear to me (I can't even tell if we're talking about the same controller action) but at a guess either that page doesn't have an id in the URL, or the routing is calling it something else, or (and this is a little messy) you intend to fall back to the current user when there is no id in the URL in which case you need to be using either params[:id] or session[:user_id] depending on what's there.
I am working through the RailsApps Stripe tutorial.
When a new subscriber is created through a devise registration controller they are then directed to their content page through a content controller. I want to use their name and email address created upon registration on their content page. But I can't seem to bring the params into the content controller.
I put#user = User.find(params[:id]) into the content_controller but I get the error "Couldn't find User without an ID".
On the error page it lists under Request Info > rack session: "warden.user.user.key"=>["User", [2],
So does that mean that ID of User #2 is being passed to the content_controller but that I can't access it?
I put#user = User.find(params[:id]) into the content_controller but I
get the error "Couldn't find User without an ID".
This error means that params[:id] = nil, i.e., you are not passing id in the params hash when redirecting the user to content page.
Possible Solutions:
With Devise you get a helper method called current_user which returns an instance of currently logged in user. So, you could directly use current_user to access the attributes of currently logged in user. For example:
To access name and email fields of currently logged in user, all you need to do is
current_user.name
current_user.email
In routes.rb, pass the id of the currently logged in user via the route of content page as below:
## Add :id dynamic segment to your content page route
get "content/:id", :to => "contents#action_name", :as => "content_page"
Since, I don't have the route details, you would need to modify the above route as per your requirement.
Next, when redirecting the user to content page after sign up just pass the currently logged in user as below in ApplicationController method named after_sign_up_path_for (You need to override this Devise method if you want to redirect the user to a different route than the default root path):
def after_sign_up_path_for(resource)
content_page_path(resource) ## Provide the path and pass resource to it
end
With Devise, you can access the currently logged in user via the current_user helper in your controller.
See documentation: https://github.com/plataformatec/devise#controller-filters-and-helpers
I can't seem to figure out how to get my routes setup properly.
In my app, I have a view that lets site owners update their address information. The new and create actions are part of the signup process and are located in the signups_controller. The edit and update actions are in the settings_controller.
When the user goes into the settings area, he/she sees only the edit form. When filled out, the user is then returned to the same form with a flash message, or error message. Here is what the controller looks like:
class SettingsController < ApplicationController
def edit
#account = current_account
#account.companies.first
#account.companies.first.addresses.first
#account.companies.first.phones.first
end
def update
#account = current_account
if #account.update_attributes(params[:account])
redirect_to edit_setting_path
flash[:notice] = "Success!"
else
render :edit
end
end
end
In my routes, I simply have:
resources :settings
The link to this area of the site is a basic RESTful named linke, with the parameter options:
edit_setting_path(:id => current_account.id)
When the user arrives to this page, they see the following URL:
http://domainname.com/settings/1/edit
When they submit the form and get errors, the URL changes to:
http://domainname.com/settings/1
Why is the URL changing -- I'd rather it not? Is there a way to make it stay the same as the initial edit view? I've tried doing a redirect on a failed update, but then I don't get the error messages.
Any ideas?
To answer your "why" question: The URL is changing because it's reflecting the URL of the failed request - which in this case is a PUT request to that URL (/settings/1). You've submitted the form and the submission of that form (correctly) points to that URL. This is a result of the RESTful routes that the helper gives you. Since the logic in your action, falls through to the render :action, there is no redirect and the form simply re-renders on the page using the same data available in this action (which is why you can see the errors).
If you want to redirect back to the edit page, yes, you will lose the errors that have been set in the #account instance variable since the redirect will reset (re-query for) the account.
You could add a route that matches a PUT to /settings/1/edit and point it to your update action and change your form etc. In short, I wouldn't recommend this, but it should work.
completely untested but attemptable:
routes.rb
put "/settings/:id/edit", :to=>"settings#update", :as=>"update_setting"
resources :settings, :except=>:update
your form would also have to submit to the update_setting_path (which also means it's not reusable for a new object... ew)
First you should read up on The Rails Guides for Routing. They will help a lot to understand why its working like that.
Secondly, to accomplish what you are trying to do, you will need to add manual routes via the match call. You'll need something like this.
match '/settings/:id/edit' => "settings#edit"
I am working on a rails application and added a simple login system according to a book.
I created the controller admin:
rails generate controller admin login logout index
It added the following routes to routes.db
get "admin/login"
get "admin/logout"
get "admin/index"
I can got to http://localhost:3000/admin/login there is no problem at all.
But when I try to login I get: No route matches "/admin/login"!
Now, the first confusing part is that the "login" method of my AdminController is not executed at all.
The second confusing part is that this code works like a charm - redirects everything to /admin/login:
def authorize
unless User.find_by_id(session[:user_id])
flash[:notice] = "you need to login"
redirect_to :controller => 'admin', :action => 'login'
end
end
Sidenotes:
I restarted the server several times.
I tried a different browser - to be sure there is no caching problem.
Try
match "/admin/login" => "admin#login"
match "/admin/logout" => "admin#logout"
match "/admin/index" => "admin#index"
(notice the leading /)
As an aside, unless you're creating a login system to learn about Rails and/or authentication, you're probably better off using something like Devise.
Following on from David Sulc's answer:
You're defining the routes as get requests, meaning to go to them you must perform a GET /admin/login request which is basically what happens when you type the URL into your address bar or follow a link that uses it.
However when you try to use these URLs in a form, the form does a POST request and because you've defined all of these as get-only requests, Rails will not be able to find a compatible route.
I definitely agree with David that you should look at an alternative system such as Devise.
I've developed a new Ruby on Rails site for my organization. I want the new Rails site to intercept incoming requests that were meant for the old site and display a message for the user indicating that the new site is launched, a link the new URL they were most likely trying to get to, and a reminder to update bookmarks.
So I'm pretty green when in comes to rails routing so I'm asking how would you do this. Is there a 'rails way'?
Here are my thoughts so far.
The old site does not use clean urls so every request goes to the default route which in the new site is the home controller with a query string. I was thinking in the controller I can test to see if params[:q] is set and then depending on what the q parameter is, search for and render the an info page directing the user to the new link. If the q parameter doesn't make sense (I don't care about catching every page on the old site, just the important ones) redirect to a custom 404 page informing the user that the link was probably for the old site, and give the user a search page.
Any thoughts, is there a better way?
I appreciate any input.
Thanks
In your Rails controller responsible for the homepage (let's say it's HomeController) add before_filter like so:
class HomeController < ActionController::Base
before_filter :handle_drupal_requests, :only => :index
Then add the handler method itself handle_drupal_requests like so.
class HomeController < ActionController::Base
before_filter :handle_drupal_requests, :only => :index
# ... other code ...
private
def handle_drupal_requests
if params[:q].present?
flash[:notice] = "You're being redirected because blah."
redirect_to convert_drupal_url(params[:q]), :status => 301
end
end
def convert_drupal_url(query_string)
# your logic for converting query string, for example:
item, id = query_string.split('&').last.split('=')
item_controller = item.underscore.split('_').first.pluralize
{:controller => item_controller, :action => "show", :id => id}
end
end
Is there a consistent way that the URLs have changed? Such as /?q=pie becoming /dessert/pie ?
If not, and it requires some sort of manual db query, you'll have to do it the way you mentioned. I would create a redirect action that catches all the paths to keep it separate from your home/index action.
Also, if you care about SEO juice, make sure to use a 301 redirect:
redirect_to dessert_url, :status=>301
You would then have to do an instant redirect (no intermediate page saying 'update your bookmark'). What I would do is the instant redirect, and put a flash[:notice] message saying to "please update your bookmarks".
Please post some examples of URLs if you need more direct examples.