Reputation: 1024
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
Upvotes: 1
Views: 1931
Reputation: 6892
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).
Upvotes: 0
Reputation: 457
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.
Upvotes: 1
Reputation: 4315
If you would like to obfuscate numerical ID's , you could take a look at this interesting discusion .
Upvotes: 1
Reputation: 145
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
Upvotes: 1
Reputation: 3376
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.
Upvotes: 0