By now you should have a blog with users, administrators and even a tag system as of part 3 in this series, so now we’re onto something for greater aesthetics. In this case, custom URLs for posts and tags.
We’ll start by running
rails g migration add_url_to_tags_and_users, this generates a migration that we can open up (usually in db/migrate/YYYYMMDDHHMMSS_add_url_to_tags_and_users.rb) and add the following inside the
add_column :tags, :url, :string add_column :posts, :url, :string
This will add columns for the url component to both the Tag and Post model and we can send these changes to the database with
rake db:migrate. Next add the following to both app/models/post.rb and app/models/tag.rb before the
validates :url, uniqueness: true def to_param url end def self.find_by_param(input) find_by_url(input) end
These tell Rails to use the
:url parameter when making and using URLs such as localhost:3000/post/welcome instead of localhost:3000/post/1 and also makes sure that the URL parameter is unique in the table. Lastly it also creates a method usable by the Tag and Post classes that allows a user to find by the url parameter with
find_by_param which will be used later.. Next edit the
update methods in app/controllers/posts_controller.rb and put
@post.url = post_params[:title].squish.downcase.tr(" ","_").gsub(/[^0-9A-Za-z_]/, '') near the top , directly above
@post.tags = ready_tags. Now we need to find every instance of
.find(params[:id]) and change it to
.find_by_param(params[:id]) allowing us to use the new
:id parameter (which will be the
:url variable) as the identifier. Do that in both app/controllers/posts_controller.rb and app/controllers/tags_controller.rb.
Next we’ll want to modify the
ready_tags private function to look like this:
def ready_tags tags = tag_params[:tag_ids].split(/,\s*/) tags_ready =  tags.each do |tag| temp = Tag.find_by_url(tag.squish.downcase.tr(" ","_").gsub(/[^0-9A-Za-z_]/, '')) if temp == nil temp = Tag.create(name: tag, url: tag.squish.downcase.tr(" ","_").gsub(/[^0-9A-Za-z_]/, '')) end tags_ready.push(temp) end tags_ready end
This makes sure it’s searching for tags by unique URL and also creates the tag with a unique URL as well.
You will also need to modify your app/controllers/posts_controller.rb
create method, wrapping everything in the method in the following block:
if post_params[:title].squish.downcase.tr(" ","_").gsub(/[^0-9A-Za-z_]/, '') == 'new' redirect_to posts_path, notice: 'Post cannot be titled "new".' else [EXISTING CODE] end
Now do similar with the
update method, wrapping it all in the following:
if post_params[:title].squish.downcase.tr(" ","_").gsub(/[^0-9A-Za-z_]/, '') == 'new' render :edit else [EXISTING CODE] end
This prevents someone creating a post that would have the URL ‘new’, which would break the resourceful routing rails uses. You’ll also need to modify config/routes.rb, removing the line
resources :tags and replacing it with:
get '/tags', to: 'tags#index', as 'tags' get '/tags/:id', to: 'tags#show' delete '/tags/:id', to: 'tags#destroy'
This non-resourcefully defines the routes used for tags (
destroy) and also allows us to create a tag labelled “new” without breaking anything.
You should now have a working, aesthetically pleasing URL system for your blog. This will likely be the last of the tutorials in this series on building a blog in Rails, the implementation you’ve created up till now should have a number of standard and useful features for blogs and you should have enough expertise to start developing your own features and branching out further.