Rails beginner config/routes.rb issue - ruby-on-rails

I am having a little trouble understanding what config/routes actually routes to. For example lets say I started a brand new project and generated a Users controller and edited my config/routes.rb to look like this:
config/routes.rb
SampleApp::Application.routes.draw do
match '/signup', to: 'users#new'
end
I start the server and as expected, it says I don't have a "new" action in my Users controller. I create one:
users_controller.rb
class UsersController < ApplicationController
def new
end
I refresh the page and as expected it tells me I need a users/new template. So my question is: do my view templates always have to be the same as the controller and action names in "(controller name)/(action name)" format (in this case users/new.html.erb)? Is it not possible to name my template something random (e.g. users/rubyonrailsmeetup.html.erb instead of users/new.html.erb) if have a controller action linked to one of the site's functions?
Also, does adding "resources :users" to config/routes.rb by default match the view template file names with the behavior I mentioned above so that views must be named after their "controller/action" names?
Sorry for the bother, I'm just trying to figure out what's part of Rails' magic and what isn't.

Rails attempts to render the template with the same name as the action by default, if no other render or redirect is invoked in the controller action. Basically, there's an implicit render :action at the end of every controller action.
But you can override this easily enough by adding an explicit render, e.g.,
render :rubyonrailsmeetup
Edit for clarity: this call to render goes in the controller code, not in config/routes

do my view templates always have to be the same as the controller and action names in "(controller name)/(action name)" format
These are defaults, you can render any view from the action by giving render :view_file_rel_path at the end of the action
does adding "resources :users" to config/routes.rb by default match the view template file names
Anything added in routes.rb is directly related upto controllers only, i.e. it matches the request and maps it to the controller/action. Logic of view comes only inside the action code

Related

Why am I getting this Ruby on Rails Error?: #index is missing a template for request formats: text/html

I am a beginner to Ruby on Rails and just web app development in general. I am having a lot of trouble trying to simply display another page. Here are my codes.
Routes file:
Rails.application.routes.draw do
root 'pages#home'
get '/recent', controller: 'recent', action: 'index'
end
Controller File:
class RecentController < ApplicationController
def index
end
end
and the "recent" html.erb file (Its directory is app>views>recent>recent.html.erb):
<h2>Recent Recipes!</h2>
Any help would be appreciated. I really tried to understand what is wrong, but I can't seem to figure it out. Thanks!
Usually when you create an action, you must have a view (erb) with the same name, so, in this case you can modify the name of recent.html.erb to index.html.erb
Also you can modify the action in your routes from index to recent, and do the same change in the RecentController.
By default Rails expects a view template in the folder with same name as the controller named after the controller's action. If you rename recent.html.erb to index.html.erb it should be ok

Rails doesn't automatically load a template when in a namespace

Take routing like the following:
namespace :auth do
get 'login', to: 'auth#login'
end
With a simple empty method in the controller:
def login
end
Without the namespace, it picks up the login template automatically with no problem. When I move it to the namespace, however, it switches to a 204 No Content response and shows a rails warning page. I can add render to my controller method, but it should be automatic. Where am I going wrong?
The path to the views must be something like:
app/views/namespace/controller/view.html.erb
So, in your case both namespace and controller have the same name, so the path to the views should be:
app/views/auth/auth/login.html
Instead of:
app/views/auth/login.html

Rails controller action duplication

I have a controller show action which does some stuff and renders a view but due to some custom routing, I need a totally different action in a totally different controller to perform the same stuff and render the same view.
I don't really wish to duplicate the code. Is there somewhere I can put it and call it from both locations?
Edit:
I basically need to run the following from Collection#Show AND also from Gallery#SplitUrl:
#collection = Collection.find_by_id(params[:id])
if #collection.has_children?
#collections = #collection.children
else
redirect_to [#collection, :albums]
end
I cannot just redirect_to Collection#Show at the end of Gallery#SplitUrl as the redirect causes my custom URL's to be lost as it's a new request.
You could put the view content into a partial (/app/views/home/_example.html.erb) and then use the render "example" command in the HomeController.
The "some stuff" code you talk about could be put into a helper file /app/helpers/... to save you from duplicating code in the two separate controllers although it could depend on what the code is trying to do in the first place.
http://guides.rubyonrails.org/layouts_and_rendering.html
This might provide more information on the subject in general.
I think the simplest approach would be to add a route definition for your new url and map that to your existing controller's action.
Something like follows:
# config/routes.rb
# Existing resource
resources :foos
# The resource in question
resources :bars do
get :show, controller: 'foos', action: 'show', as: bar_foo_common_show
end
Note that this will give you /bar/:id, where id represents a bar resource. So in your foo#show action, your finder needs to be executed on appropriate class. This is when a few lines of hacky codes get added, for e.g. checking for request referer.
I think moving the common code to a function in possibly application_controller and calling that function from both show action would be cleaner approach, but based on my understanding you already have a similar scenario except for the common code in application_controller, and would like to try out a different approach!

How to create view in RoR if skipped during controller generation

When I run this:
rails generate controller hello index
it no doubt generates hello controller, but accidentally when I run another command like this:
rails generate controller world
it creates the world controller successfully, but missed the Route "world/index" like as "hello/index". For this mistake I need to use destroy controller and then generate it once more, is thr some kind of mid way command that I can generate if forgotten something rather than destroying and creating every time.
This command
rails generate controller contact-us index
creates a route as contact_us/index or contact_us after changing routes.rb under config folder. How could I create a more SEO friendly URL in RoR? Like localhost:3000/contact-us?
I am working on some very basic rules to follow RoR..like 3 static pages (Home, About us, Contact Us) Just simple html content to understand more, will certainly add more features to it as well.
localhost:3000/home
localhost:3000/About_us
localhost:3000/contact_us
I created this via creating home, About_us, contact_us controller command and then changed html in views. Since I am on an initial phase, I read somewhere for static pages we can create this in our public like what we have error pages there in the folder or the approach im using is correct?
when you use rails generator it will create controller and view folder for it
rails generate controller test
will create test_controller.rb and view/test folder
rails generate controller test index
will create test_controller.rb and view/test/index.html.erb file as well as define a route for you
However what its sounds like you are trying to do is have single controller with static pages what i would suggest you do is generate home_controller with home, aboutus, and contact actions and than map the routes to them like so
rails generate controller home
controllers/home.rb
HomeController < ApplicationController
def index
end
def about_us
end
def contact
end
end
routes.rb
match '/home', :to => 'home#index'
match '/About_us', :to => 'home#about_us'
match '/Contact_us' , :to=> 'home#contact_us'
and than define your views in
views/home/index.html.erb
views/home/about_us.html.erb
views/home/contact_us.html.erb

Identical Files behave differently due to link with controller

I am building my first app with ROR and stumbled upon a couple of problems due to my understanding of the MVC
I have a page to add a new item, and this works fine, rails magically hooks it up to the items controller and somehow by magic it knows to look in the method 'new' as the page is called new.
But this layer is confusing me, as i need to now create a different version of new, same functionality but with a different look so to use a different layout to application.html.erb
So i attempt to create a copy of new.html.erb and create bookmarklet.html.erb - both contain exactly the same code: a link to a form. but of course bookmarklet will error on me because it does not have that link in the controller - how do i 'wire' up bookmarklet so that i can call the new method and so that it can behave in a similar way to the identical new.html.erb
Also, how can i tell the new bookmarklet.html.erb to ignore the application.html.erb and get its layout from another file?
thanks in advance
The magic happens in the routes. Rails uses something called RESTful routes, which is taking HTTP verbs and assigning standard actions to it. the new action is a GET request in HTTP speak, and if you are using scaffolding or following REST, will have the ruby call to build a new object in the controller, as an instance variable so you can use it in your view.
You have to tell rails routes that you want to BREAK this arrangement and to let /items/bookmarklet be used in the controller.
In your routes.rb file replace resources :items with
resources items do
member do
get 'bookmarklet'
end
end
In your controller put:
def bookmarklet
#item = Item.new
render :template => "bookmarklet", :layout => "different_layout" # or you can put this on the top of the controller, which is my style, but whatevs.
end
You should look into partials, if you are doing this as they clean up your code immensely.
A better way to think of things is to start with the controller instead of the view html.erb files. So each public method in your controller is effectively a page or action in the site. When you need a new action or page, add the method to the controller first. Then create the relevant view files.
So in your controller you'll need something like:
def bookmarklet
#item = Item.new(params[:item])
#item.save
render :template => "items/bookmarklet.html.erb", :layout => "different_layout.html.erb"
end
Normally you don't need to call render manually in the controller, but since you want a different layout than the default you need to specify it using render.

Resources