how to route your sub-folder in views Ruby on Rails? - ruby-on-rails

Can anyone please shed some light on how to route your sub-folder's .html.erb files?? which is placed like this:
view/pages/en/index.html.erb
and to route this i am doing following things on route.rb
match ':lang/index', :to => 'pages/en#index'
and for a link code, I have this on the header
<%= link_to "Home", index_path %>
The error i am getting is
Routing Error
uninitialized constant Pages
routes:

Namespaces will organize your code and views in subfolders: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
If just need only the views/pages folder organized that way, you could do in PagesController something like:
render "#{I18n.locale}/#{action_name}"
A question: why would you like view/pages/en/index.html.erb instead of view/pages/index.en.html.erb? That would work out of the box.

UPDATE
This is how it works for route.rb:-
match ':lang/index', :to => 'pages#index'
Render it on your controller:-
def index
render "pages/en/index"
end
def about
render "pages/#{params[:lang]}/about"
end

AFAIK, There is no way to route to a view. You can route an URL to a controller's action. That action is responsible for rendering the views.
you can use namespaced routing to put the resources in the sub folder.
...
What i wanted to write already written by #TuteC. Just follow that link and yes you can get language specific thing out of box as he explained.

I have been struggling with this for a while and finally figured out an easy solution:
config/routes.rb
get 'pages/:first/:second/:third' => 'pages#show'
Then in your PagesController
def show
render "/pages/#{params[:first]}/#{params[:second]/#{params[:third]}"
end
Then in your views it will render any of the following:
pages/index => pages/index.html.erb
pages/index/en => pages/index/en.html.erb
pages/foo/bar/hello-world => pages/foo/bar/hello_world.html.erb
The best thing about this is that it is simple and you can extend it indefinitely. Allows easy cleaning up of the views folders if all you are doing is rendering basic templates.

Related

Route Controller#show method like how Controller#index would in Rails

Hi guys I am new to rails. Sorry if I can't define this question properly.
What I wanted is for:
domain.com/posts/1-sample-post
to be routed like this:
domain.com/1-sample-post
How do I achieve this in rails routes? I've tried searching for this for almost 3 hours. This is very easy in PHP frameworks. I thought this is easy in Rails too.
I forgot to mention I have High_voltage gem installed in my app for my static pages.
Did this:
#routes.rb
resources :posts
get '/:id' => 'posts#show'
Now my High_voltage pages could not be rendered.
Update Solution:
So here is what we did in the routes:
Rails.application.routes.draw do
resources :authors
constraints(lambda { |req| Author.exists?(slug: req.params["id"]) }) do
get '/:id' => 'authors#show'
end
devise_for :users
resources :posts
constraints(lambda { |req| Post.exists?(slug: req.params["id"]) }) do
get '/:id' => 'posts#show'
end
end
Note that it is important to only use an exists? query here as it is very fast than other methods, so it won't eat that much loading time to render a record.
Special thanks to the guys below who helped a lot. Nathanvda, rwold, and Tai.
So the other answer correctly suggested something like
get '/:id', to: 'posts#show'
But this is a catch-all route and if there are no other routes defined this will catch all routes, also your HighVoltage, if it is configured to serve pages on root. You now have two catch-alls: one to find a static page and one to find a post.
Best solution in this case, imho is to make the static pages explicit (since I am assuming there will not be that many?)
get '/about' => 'high_voltage/pages#show', id: 'about'
get '/:id' => 'posts#show'
If you have a lot of pages, it seems easiest to just present the high-voltage on a different route? E.g. something like
get '/pages/:id' => 'high_voltage/pages#show'
get '/:id' => 'posts#show'
In both of these cases, since we use explicit routing, you would have to disable the default routing in the high-voltage initializer:
# config/initializers/high_voltage.rb
HighVoltage.configure do |config|
config.routes = false
end
[UPDATE: add special controller to consider both posts and pages]
Add a HomeController like this:
class HomeController < ApplicationController
# include the HighVoltage behaviour --which we will partly overwrite
include HighVoltage::StaticPage
def show
# try to find a post first
#post = Post.where(id: params[:id).first
if #post.present?
render 'posts/show'
else
# just do the high-voltage thing
render(
template: current_page,
locals: { current_page: current_page },
)
end
end
end
Of course I did not test this code, but I think this should get you started. Instead of doing the rendering of the post, you could also redirect to the posts-controller which is maybe easier (and you will use the PostsController fully) but adds a redirect and will change the url.
In your routing you will then have to write
get '/:id', 'home#show'
In your routes.rb file:
get '/:id-sample-post', to: 'posts#show', as: :sample_post
assuming that posts is your controller and show is the action that calls the view for your article with the given id.
EDIT AFTER OP COMMENT:
The as: :sample_post clause should create a helper sample_post_path that can be invoked as <%= link_to "Show", sample_post %>.

Rails controller using wrong method

I'm working on a Rails project that is giving me some problems. I've got a controller characters_controller.rb that has two methods.
class CharactersController < ApplicationController
before_action :authenticate_player!
def view
#character = Character.find(params[:id])
unless #character.player_id == current_player.id
redirect_to :root
end
end
def new
end
end
I've got routes set up for each of those.
get 'characters/:id', to: 'characters#view'
get 'characters/new', to: 'characters#new'
The first route works fine. I can get go to /characters/1 and I'm shown the appropriate view and the requested information. If I visit /characters/new I'm shown an error that references characters#view.
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
and
app/controllers/characters_controller.rb:6:in `view'
So /characters/new is trying to get a Character from the database with an id of "new" but that doesn't work well. Any idea what I may be doing wrong?
Order matters in routes.rb, the router will find the first route that matches.
In your case, it would never go to characters#new, because the line above it will always match.
A simple solution would be to swap the two lines.
A better solution might be to use resource routing as documented in the Rails routing guide.
Rails parses routes sequentially and therefore it is considering 'new' as the :id for characters/:id route (which encountered first).
Just swap the order of routes as follow:
get 'characters/new', to: 'characters#new'
get 'characters/:id', to: 'characters#view'
If using this order in your routes.rb, for /character/new request, rails will understand that request is handled by view action with paramas[:id] = 'new'
Let characters/new before the other will resolve your problem:
get 'characters/new', to: 'characters#new'
get 'characters/:id', to: 'characters#view'
Try to use resourceful routes, much cleaner:
resources :characters, only: [:new, :show]
Also I suggest rename def view to def show to follow rails convention
Just use
resources :characters, :path => "characters"
in your routes.rb

Referring to a nested resourse

I have a nested resource:
resources :res1 do
resources :res2
end
And I have a custom action in res2:
def my_action
end
which doesn't appear in the list of the pre-generated paths (there is no res1_res2_my_action_url url). I want to refer to my_action using controller and action notation but the following doesn't work:
url_for(controller: [:res1, :res2], action: :my_action)
Why is that?
The resources directive in your routes file will only create default routes for your controller.
#index
#new
#create
#show
#edit
#update
#destroy
If you want to add custom routes, you'll have to declare them like so:
resources :res1 do
resources :res2 do
get :my_action
end
end
you can hard code a specific route that points to action and controller:
get '/pathname', to: 'controller_name#my_action'
Try running rake routes and see what o/p you get,a try to apply in your view
get 'my_action' => "res2#my_action"
and then write
:url => my_action_path

default URL for a model in rails?

I have a class Post
I want the default URL of each posts to be http://domain.com/9383 instead of http://domain.com/posts/9383
I tried to fix it in the routes. I manage to accept domain.com/222 but if I use <%= url_for(#posts) %> I still get domain.com/posts/222
How can I do it? Thank you
You can't change the behaviour of url_for(#post) with routes. url_for will assume a map.resources setup if an ActiveRecord instance is passed to it.
You should rather do this:
# routes.rb
map.post ":id", :controller => "posts", :action => "show"
# named route
post_path(#post)
# full link_to
link_to #post.title, post_path(#post)
If you're using url_for, there's no way to tell it to omit the /posts/ section. I think you would need to create helper, maybe in application_helper.rb
def post_url(post)
"/#{post.id}"
end
Overriding url_for seems to not be considered a best practice in Rails, although it seems terribly convenient to me. Here's a description of how to do it by customizing ApplicationController: http://arjanvandergaag.nl/blog/generating-fancy-routes-with-rails.html

rails routing controller action change

I'm struggling here with a problem:
I have a controller questions which has action new.
Whenever I need to create new question, I'm typing
/questions/new
What changes to routes.rb should I make to change the URI to
/questions/ask
Thank you.
Valve.
Try this:
map.ask_question '/questions/ask', :controller => 'questions', :action => 'new'
Then you'll have a named route and you can:
link_to "Ask a question", ask_question_path
If you are using RESTful routes maybe you'd like to use map.resources for your questions.
To rename the action urls you may do this:
map.resources :questions, :path_names => { :new => 'ask', :delete => 'withdraw' }
(I added delete for the sake of the example)
Which version of rails?
Generally the default route should catch anything like /:controller/:action, so you could just create an ask method in your questions controller. Take a look at the api documentation for named_route and map_resource if you want something a bit smoother to work with.

Resources