Manage manualy Rails router for SOE and multilingual - ruby-on-rails

I'm a beginner with Rails, and I ready all this very usefull tutoriel (French) But I have some other question..
I learn how the basic Rails router works (based from Controller name) :
RequĂȘte HTTP URL Action
-----------------------------------
GET /users index
GET /users/1 show
GET /users/new new
POST /users create
GET /users/1/edit edit
PUT /users/1 update
DELETE /users/1 destroy
But I want make some modifications :
1/ SOE
I need to update route for user retrieve (show, update, ..) and i want use #user[:username] on URI instead of #user[:id]
So in my case : /users/arthur instead of /users/1
2/ Multilingual
On the same type of problem, i want add one the start of the URI the ISO code for each country (ex : /fr/users/) and create alias on my URI.
For example, before the Rails router was initialized I want update all routes like :
/utilisateurs/... -> /users/...
/produits/... -> /products/...
Can I do it easly ?! And these changes may be applicable by the link_to function ?
So if i'm call like_to #user ( with #user data : {'name'=>'arthur', 'lang'=>'fr'} ) the function should return /fr/utilisateurs/arthur instead of /users/1
Thank you all for helping !

You can use Translated Paths for the multilingual definitions found here. As for the use of username for the param you can follow this, basically you override to_param and that will be used to generate the url when using link_to and other helpers.

Related

Incorrectly routing /index to /show in Rails

There must be an obvious answer to this, but I'm at a loss.
I have a Rails app which tracks sites. For whatever reason, localhost:3000/sites leads to my index page. However, localhost:3000/sites/index leads to my show page.
Why is this?
Below is the routes file:
Rails.application.routes.draw do
resources :sites
Below is the sites controller:
class SitesController < ApplicationController
def index
end
def show
end
end
In views/sites, there is the index.html.erb and show.html.erb files. The former displays at /sites, the latter displays at /sites/index (and /sites/show as one would expect).
Thanks for any help!
UPDATE:
When I rake routes, I get:
Prefix Verb URI Pattern Controller#Action
sites GET /sites(.:format) sites#index
POST /sites(.:format) sites#create
new_site GET /sites/new(.:format) sites#new
edit_site GET /sites/:id/edit(.:format) sites#edit
site GET /sites/:id(.:format) sites#show
PATCH /sites/:id(.:format) sites#update
PUT /sites/:id(.:format) sites#update
DELETE /sites/:id(.:format) sites#destroy
These routes are what one would expect, but I guess I'm just surprised that sites/index presumes index is an :id and therefore routes the request to show.
I suppose I had never explicitly encountered that behavior before.
There are 7 basic actions in a controller by default, only 2 of them are matched by name in the url - (new and edit). These 2 are HTML constructs, they are just a way of rendering a form.
The other 5 (index, show, update, create, destroy) are the more basic routes and do the work to display and modify resources. They are referenced by only two url patterns (the two patterns you mentioned above - eg '/sites' and '/sites/:id'). They are differentiated by the method that goes along with the request: (Patch, Post, Get, Delete). So, "/sites" would be used for create and index. "/sites/:id" would be used for show, destroy, and update.
The action in the controller is not referenced by the url exactly - the url pattern and the request method together are used to call the associated controller method.
In the request "/sites/index", as the string "index" is in the url, the only route that matches is one that has a variable after "/sites/". :id is just a variable, not necessarily an integer. Since the request was a GET, the first (and only) route match is sites#show. "index" will be the value of params[:id] passed into the show action.
This is the way routing works in Rails. Take a look at Rails routing to get a better understanding of how this works. Especially the
Rails resource routing section.
Generally when you setup a resource route as you did the urls would be as follows:
example.com/sites #=> index page
example.com/sites/:id #=> show page. A specific site, where :id would be the unique identifier
# Here's an example URL with a specific site
example.com/sites/stackoverflow
Your index page is at: localhost:3000/sites
Navigate to localhost:3000/rails/info/routes to see your full app routes in development mode.

Get current path name in Rails

I would like to be able to get the name of the current route in a request in Ruby on Rails. I've found ways I can access the controller and action of the request, but I would like to access a string or symbol of the name.
For example, if I have a users resource;
If I go to /users/1 I would like to be able to get users_path
If I go to /users/1/edit I would like to be able to get edit_users_path
I simply want to retrieve the name of the current route on a given request.
The following code will give it to you.
Rails.application.routes.recognize_path(request.request_uri)
Note that there are a couple of exceptions that can get thrown in ActionDispatch::Routing::RouteSet (which is what is returned from Rails.application.routes) so be careful about those. You can find the implementation of the method here.
You can use the following methods to get the current url in your action but none of them will give you the name of the route like users_path
request.original_url # => www.mysite.com/users/1
request.request_uri # = > /users/1
I had to use request.original_fullpath (Rails 5.2)
You can use the current_page? method to achieve this.
current_page?(user_path(#user))
current_page?(edit_user_path(#user))
Here's a link:
current_page? method

Default Routing in rails

According to http://guides.rubyonrails.org/routing.html:
HTTP Verb Path Action Used for
GET /photos index display a list of all photos
GET /photos/new new return an HTML form for creating a new photo
POST /photos create create a new photo
GET /photos/:id show display a specific photo
GET /photos/:id/edit edit return an HTML form for editing a photo
PATCH/PUT /photos/:id update update a specific photo
DELETE /photos/:id destroy delete a specific photo
How does rails know when a PATCH/PUT REST is received. I understand the get/post but PATCH/PUT I cannot figure it out. Is something being done internally, like in the input.
Rails figures out which method to call based on whether the form submitted is a form for a new record that has not yet been saved or for a record that already exists in the database.
Read about "resource routing" in the document you referenced at the top of your post.
Also, run rake routes to see how rails is currently configured to route.
In The Terminal Type:
$rake routes
and hit enter
Prefix Verb URI Pattern Controller#Action
root GET / welcome#index

How to setup routes when the controller only has edit and update?

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"

How to pass a param from one view to another in Ruby on Rails, using POST

I feel like this should be an easy thing to figure out, but I'm stumped.
I have a value in a Project's instance variable called ID. I want to pass that value to a new Photos page to associate each photo that is created with that specific project, but I don't want the Project's ID to show up in the visible query string.
I've tried using link_to and button_to, but (I suspect) since I'm using "resources :photos" in my routes, all of the requests that come to photo#new are being interpreted as GET instead of POST.
Helllllllllllllllp!
Thanks to anyone that can give me some insight, I'v been killing myself over this for the past hour or two already.
--Mark
The usual way to do this in Rails is to create a route that matches urls like this: /projects/4/photos/new. Doing something else is up to you, but Rails makes it really easy to do stuff like this. See more on routes in Rails 3.
Your entry in routes.rb should look something like this:
resources :projects do
resources :photos
end
Then in app/controllers/photos_controller.rb you'd have this for the "New Photo" form page:
def new
#project = Project.find_by_id(params[:project_id])
end
and this for the action that the form in app/views/photos/new.html.erb submits to:
def create
#project = Project.find_by_id(params[:project_id])
#photo = #project.photos.create(params[:photo])
end
Of course you'll want to have error handling and validation in here, but this is the gist of it. And remember, use GET for idempotent (non state-changing) actions (e.g. GET /projects/4/photos), POST for creating a new thing (e.g. POST /projects/4/photos), and PUT for updating an existing thing (e.g. PUT /projects/4/photos/8).

Resources