I'm trying to build a little todo app with rails 4 and react. Nothing really hard, it's just a beginning to learn how to use react with rails, but I have difficulties on how to code my rails controllers.
The two urls reachable at the moment are "mysite.local" to display all the todos, and to "mysite.local/todos/1" to display a specific todo with more details.
I have a Todos controller that I use to respond to the AJAX calls related to the todos.
The view that contains the react app is not a "Todos" view because I will add more than just todos in the futur and the react app will have to handle everything.
What I want to do is simple: I want rails to always render the view with the react app regardless of the url used to reach the website. All the controllers in my app (like the Todos controller) are just used to retrieve JSON datas that will be manipulated by react.
The solution I found is to put the react app in the application layout. That way, it will always be present when someone go on the website for the first time. Since it's in the layout it will not be rendered again, the react app can do its job.
My controllers then looks like this:
class TodosController < ApplicationController
def index
respond_to do |format|
format.html
format.json { Todo.all }
end
end
def create
respond_to do |format|
format.html
format.json { Todo.create(todo_params) }
end
end
def show
respond_to do |format|
format.html
format.json { Todo.find(params[:id]) }
end
end
private
def todo_params
params.require(:todo).permit(:content)
end
end
With a controller like this, I can make my AJAX calls and get a JSON, which is the only datas my controller will send, and at the same time I can still reach "mysite.local/todos/1" and rails will do nothing except rendering an empty view.
This method works, but I don't like it because the controller render a view for each action. When someone reach the website for the first time, an empty view will be rendered. Even if the view is empty and it will not display anything on the browser, rails still have to do all the process to render the view. I don't know if this process really cost something, but I don't like the fact that my application is doing something useless.
Is there any way to tell rails to literally do nothing if the format action is html? (= not rendering the "index", or "show" view?)
Or is there a better way to do what I want to do?
Thanks
EDIT
Thanks to gobluego, I modified my application a little. I created a Front controller to handle the client part. Then I moved my Todos controller in an api folder.
Here is my routes.rb file now:
root "front#index"
namespace :api, constaints: { format: 'json' } do
resources :todos, only: [:index, :create, :delete, :show]
end
get '*path' => "front#index", via: :all
and my new Todos controller:
class Api::TodosController < ApplicationController
respond_to :json
before_action :ensure_json_request
def index
respond_with Todo.all
end
def create
respond_with Todo.create(todo_params)
end
def show
respond_with Todo.find(params[:id])
end
private
def todo_params
params.require(:todo).permit(:content)
end
def ensure_json_request
return if request.format == :json
render :nothing => true, :status => 406
end
end
That way, any url is handled by front#index, except all the apis urls, which is what I want. To ensure that nothing is rendered if, for example, someone tries to reach mysite.local/api/todos in the browser, a before_action is used and it render nothing if the format is not json.