what is (.:format) appended to url path during rake routes? - ruby-on-rails

When I run rake routes, I get something like this:
signin /signin(.:format) application#signin
What is the (.:format) in the middle?

It's an optional format. It matches URLs like:
/signin
/signin.html
/signin.json
This format can then be used in the controller. For example:
class UsersController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render xml: #users}
format.json { render json: #users}
end
end
end
This code snippet is from Action Controller Overview. See more details in the routing guide.

Related

Rails routes: json endpoint naming convention

I have an endpoint that renders json:
def controller_method
render json: json_response
end
However, I am curious about the naming convention of the route. The following naming leads to ActionController::UnknownFormat Controller#controller_method is missing a template for this request format and variant.:
get '/controller/controller_method.json', to: 'controller#controller_method'
However, I successfully get the json when the route is named:
get '/controller/controller_method_data', to: 'controller#controller_method'
Am I not allowed to put .json in the url routes? Any way that I can allow .json be the name of the route?
There is a much easier way to respond to different formats - just use ActionController::MimeResponds
get '/controller/controller_method', to: 'controller#controller_method'
class Controller < ApplicationController
def controller_method
respond_to do |format|
format.json { render json: { hello: 'world' } }
format.html # renders the view implicitly
format.txt { render plain: 'Hello world'}
end
end
end

Rails Tutorial NoMethodError in Users#index

I'm following along with the Rails tutorial by Michael Hartl. We just created a Users database (this first part of "demo_app"), but when I start the server and navigate to the new users page I get the following error:
NoMethodError in Users#index
and the application trace:
app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__2922823401409246272_70101530338460'
app/controllers/users_controller.rb:7:in `index'
I really have no idea how to decipher these error messages but here is my users_controller file:
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
....
....
Line 7 is the respond_to do |format| line. Any thoughts? Complete newbie to Ruby and Rails (figured I'd learn Ruby on the fly).
P.s. it's not a syntax error. I know that much.
Haven't you forgot one end?
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
I believe your problem is in not closing out the respond_to do |format| block. Should be:
def index
#users = User.all
respond_to do |format|
format.html #index.html.erb
format.json { render json: #users }
end
end
I tried to compare your code with mine, but I am not sure where you are in the tut. In chapter 2, we built a demo app, but in my Users.controller there is no 'respond_to … block.
In that case, you should probably close the def index with end, but I am not sure where your respond_to block should go in that case.
In chapter 4, where there IS a respond_to block, I don't have an index-method in my Users.controller
So, could you tell what chapter you are working in? And maybe post the complete Users.controller file?
Does your config/routes.rb file contain a line declaring that your urls /users/* should dispatch to your UsersController?
If the line doesn't exist, you should add in config/routes.rb
resources :users

Change Params[:id] in Ruby on Rails

I have a Ruby on Rails application where you can create 'posts'. I started of by using the scaffold generator to give generate the title which is a string and the body which is the content.
Each 'post' has a url of the id, for example /1, /2, /3, etc.
Is there a way to change it to generater a string of random characters and numbers, for example /49slc8sd, /l9scs8dl, etc?
Here is what I have for the posts_controller.rb
class PostsController < ApplicationController
# GET /posts
# GET /posts.json
def index
#posts = Post.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
# GET /posts/1
# GET /posts/1.json
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
# GET /posts/new
# GET /posts/new.json
def new
#post = Post.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #post }
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render json: #post, status: :created, location: #post }
else
format.html { render action: "new" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
end
And here is what I have in the post.rb model
class Document < ActiveRecord::Base
attr_accessible :content, :name
end
If you want your models not to have their primary key id in a predictable sequence, you can generate the id based on uuid or guid with the help of something like http://codesnipers.com/?q=using-uuid-guid-as-primary-key-in-rails
However you can also route based on any other property which uniquely identifies the resource which is the recommended approach if in case you dont want to expose the database identifiers in your routes
person/:person_random_token, :controller => :persons, :action => :show #adding this in your route file directing to the controller where you can use params[:person_random_token] to uniquely identify your person object in Persons model
In your controller's action you can say
Person.find_by_random_token(params[:person_random_token]) #assuming random_token is your column name
to get the Person object
If you would like to obfuscate numerical ID's , you could take a look at this interesting discusion .
You should also be aware of the to_param method for ActiveRecord::Base objects.
Basically, Rails calls this method on your objects to know what to put in the URL and params[:id]. By default it is just the primary key of the record in the database. Say you override it as such:
class Post < ActiveRecord::Base
def to_param
return id*100
end
def self.find_by_new_id(n)
return self.find(n/100) # really you'd want to handle strings and integers
end
end
The first record in your database would have url /posts/100.
In your controller, to retrieve the object you just do
#post = Post.find_by_new_id(params[:id])
(Of course you could override the default find method as well, but that is probably frowned upon.) Basically the to_param method transforms your id and the new finder undoes it. Usually you just point to another database column that has been automatically populated via a hook when the record is created. This is what is described in the link posted by Qumara otBurgas.
It's not clear what you are asking here. The path to the action specified in the routes does not require the id passed to be of a certain format. You can pass non-numeric ids if you want and within your action use the id however you'd like. Maybe if you supplied more info about the routes and actions we could understand what you are asking for.
There is a number of ways how you can generate a random string in Ruby.
Now, to the second part of your question. If you want to access your posts using a route like /post/rndm5tr, you can simply change this line of code inside your controller:
#post = Post.find(params[:id])
to
#post = Post.find_by_randomness(params[:id])
Now, simply create a migration: rails g migration AddRandomnessToPost randomness:string and run rake db:migrate (or bundle exec rake db:migrate, depending on how it's set up).
Of course, you are free to name the field whatever you want, randomness is just a random name I used. I think the common convention is to call them slugs or tokens, but I might be wrong.
Now, add a method to before_create in your model to generate the random string and add it to the soon-to-be-saved Post object (using one of the examples from the above link). It would be wise to check if the string you're generating is already taken (you could write a recursive method that calls itself again if a post already has the random token).

rails reusing view templates

A rails newbie here
I have 2 actions in my controller 1) index 2) refine_existing.
Both of them show the results in the same format.
How do I reuse the index.html.erb file?
When I try the following, it complains about refine_existing.erb not being present.
def refine_existing
...
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #results }
end
end
my index action looks like this
def index
#some logic to get #results
#set some session variables etc.
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #results }
end
end
Do I have to refactor my index view to contain partials that
a) make the headers
b) render #results
and reuse them?
Even though, both index.html.erb and refine_existing.html.erb will look exactly the same
Is there any way I can say in my refine_existing action to use index.erb view?
thanks in advance
By convention, if you don't specify a template name Rails looks for one matching the action. You can override this by calling render explicitly with the desired template name. The only wrinkle is that the path is relative to TEMPLATE_ROOT, which is normally app/views:
def refine_existing
...
respond_to do |format|
format.html { render :template => "<table_name>/index.html.erb" }
end
end
replacing table_name with the "tablized" form of the model. E.g. if your controller is PostsController, then posts. So your template would then live in app/views/posts/index.html.erb -- if you've customized paths somehow adjust as necessary.

Add JSON support to Rails app

I am experimenting with Rails and was wondering what's needed to allow/add support for JSON requests?
I have a vanilla installation of Rails 2.3.5 and the default scaffolding seem to provide support for HTML & XML requests but not JSON.
class EventsController < ApplicationController
# GET /events
# GET /events.xml
def index
#events = Event.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #events }
end
end
# GET /events/1
# GET /events/1.xml
def show
#event = Event.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #event }
end
end
...
I'm new to this but it would appear as though i would need to add a format line in each method along the lines of:
format.js { render :js => #event.json }
couldn't this be done automatically? perhaps there's a template somewhere i need to update...or a flag i can set? Or perhaps, and most likely, I've missed the boat entirely?!?
You do:
format.json {render :json=>#event}
That will render the default activerecord JSON for the model
The option of ease of use is that you can write a private method which takes the format object and an object to render and then, based on the format, renders different things. Example:
class MyController<ApplicationController
def show
#event=Event.find(params[:id])
respond_to do {|format| myRenderer(format,#event)}
end
...
private
def myRenderer(fmt,obj)
fmt.json {render :json=>obj}
fmt.html
fmt.xml {render :xml=>obj}
end

Resources