How to organize a routes.rb file in Rails

If you have a small Ruby on Rails application, you probably don’t have much need to organize your routes.rb file. However if your project is large, you probably have a somewhat complicated, and quite frankly, messy routes file. Sometimes its hard to really understand where your routes are, especially when you are working with hundreds of lines of routes. I had such an issue in a recent project I was working on.

The project has multiple contexts within it, and each on of them has their own set of routes. These were all smushed into the main routes.rb file along with the normal base routes. What I wanted to do was create multiple routes files under a config/routes folder and split them up there to make them more manageable. Here is an example of how to split them up:

# config/routes.rb
Rails.application.routes.draw do
  # Some base routes here
  resources :pages


  extend AdminRoutes
  extend UserRoutes
  extend OrganizationRoutes
end

As you can see, we have a basic routes file, however you will notice that there are a few extend Class directives in there. These will load in the corresponding class file, that I will have stored in the config/routes folder. Here is an example of what one of those files looks like.

# config/routes/admin_routes.rb

module AdminRoutes
  def self.extended(router)
    router.instance_exec do
      authenticate :user, lambda { |u| u.admin? } do
        mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
        mount Sidekiq::Web => '/sidekiq'
      end
    end
  end
end

I will show you one more, since the AdminRoutes file is mostly just the entry point for some mounted Rails Engines, and not normal resources

# config/routes/user_routes.rb

module UserRoutes
  def self.extended(router)
    router.instance_exec do

      authenticated :user do
        root to: "dashboard#show", as: :authenticated_root
      end

      devise_for :users,
        :skip => [:registrations],
        :controllers => { :invitations => 'user/invitations' }
      as :user do
        get '/user/new' => 'user/registrations#new', as: 'new_user_registration'
        post '/user' => 'user/registrations#create', as: 'user_registration'

        get 'user/edit' => 'user/registrations#edit', :as => 'edit_user_registration'
        put ':id' => 'user/registrations#update', :as => 'registration'

        delete '' => 'user/registrations#destroy'
      end

    end
  end
end

The last thing we need to do, is make sure that the new config/routes folder gets picked up by rails. Add the following line to your config/application.rb file

config.autoload_paths += %W(#{config.root}/config/routes)

Hopefully these examples help you with splitting up a large routes.rb file into smaller, more manageable pieces. Let me know in the comments if this helps, or you have any issues getting this to work.

WordPress vs Everything Else – Why you should not build your own blog

Being a web developer, the idea that I would use a blogging platform always made me cringe a little bit. I mean, why not. I had the skills to create my own blog that I could customize exactly how I wanted. And thats where I started originally.

I wanted to learn a new language, Ruby on Rails, and what better way to start than follow one of many “How to build a blog with Ruby on Rails” posts that were littered across the internet at the time. So I did that for a while, and back then (circa 2006-ish) there wasn’t much in the way of deployment and server-ease like Heroku, so I had to manually do all that myself, with FastCGI and eventually Mongrel.

 

I quickly realized that all the customization that I wanted to build, I no longer wanted to build. I just wanted a place to share some ideas and not worry about the management of another web application. I was already doing that in my day job. At this point, I decided to use WordPress, but this wasn’t my final decision, I would come to find out.

I had started using WordPress for a while, but again, the developer bug crept back in. I wanted to find something else that wasn’t so “WordPress-y”. I tried some other things like Joomla, Typepad, Jekyll and other static blogging codebases. I eventually settled on using Bolt, which is another PHP based blogging platform. I have no idea why….

I used that for a while and finally got tried of the lack of community around it and some customizations that I missed, that were available with WordPress out of the box. After battling with that for a while, I decided to move back to WordPress and import all my data back into it. I think this is where I’ll live now and its just so flexible and easy to just start writing.

I am in no way saying, don’t write a blog if you want to learn a new language. It’s a super simple idea that I think anyone can grasp, and you don’t want to be overwhelmed while learning a new language. I would just recommend to not bother using it for your official, public blog that you want to write on all the time.

So at the end of the day, I am not a super fan of having a PHP based blog, when I mostly code and write about Ruby on Rails code, but the fact that I pretty much never have to dig into the internals of WordPress, makes it worth it in the end.

How to create a Sidekiq service application without Rails

Sometimes you want to create a small Sidekiq service to process requests, without all the extra bloat (and memory usage) from a Rails framework. It turns out that creating such service is not all that hard to do. Create your application using the folders and files below as your starting point.

Gemfile

# Gemfile
source 'https://rubygems.org'
ruby "2.5.0"
git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
  "https://github.com/#{repo_name}.git"
end

gem "sidekiq"

config/sidekiq.yml

---
:concurrency: <%= ENV["CONCURRENCY"] || 25 %>
:queues:
 - default

config/application.rb

# config/application.rb

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)

require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
Bundler.require

ENV["RACK_ENV"] ||= "development"

module Example
 class Application
   def self.root
     @root ||= File.dirname(File.expand_path('..', __FILE__))
   end

   def self.env
     @env ||= ENV["RAILS_ENV"] || ENV["RACK_ENV"] || ENV["ENV"] || "development"
   end

   def self.logger
     @logger ||= Logger.new(STDOUT)
   end
 end
end

require_relative "initializers/sidekiq"

config/initializers/sidekiq.rb

# config/initializers/sidekiq.rb

Sidekiq.configure_server do |config|
  config.redis = { url: ENV["REDIS_URL"] }
end

app/workers/my_worker.rb

# app/workers/my_worker.rb

class MyWorker
  include Sidekiq::Worker

  def perform(*args)
    # Do work here
  end
end

Once you have created those files, then you can run the following on the command line:

bundle exec sidekiq -e ${RACK_ENV:-development} -r ./config/application.rb -C ./config/sidekiq.yml

If you want to enqueue jobs from another application using Sidekiq, its as easy as:

Sidekiq::Client.enqueue_to "default", MyWorker, "param_1" => "1", "param_2" => "2"

When you have all this working, then you can start adding things like your database connections and other gems and code to the worker. Let me know if this helps anyone or if you run into any problems!

Open Source Application Performance App

Its been a while since I have posted anything and I thought I would share with you a small project I have started to work on. Its called app_perf and its a little application that is intended to do application performance monitoring. Right now I am only supporting Ruby via the agent gem, but other languages can easily be added to post metrics to this as well. I encourage anyone interested to clone the project, submit any PR’s and help out making this a lot more full featured. Here is the Github link, https://github.com/randy-girard/app_perf

Here are some screen shots:

Let me know what you all think!

How to merge strings just like ActiveRecord conditions do

While you can achieve the same functionality using sprintf, this may provide a cleaner approach and one that you are more familiar with. This will allow you to build a string the same way you can use ActiveRecord and the :conditions option.

Basically how this works is by overriding the Array class and adding a method to merge the string and values together into unified string! Enough talk, lets see some code:

class Array
  def merge
    statement, *values = self
    expected = statement.count("?")
    provided = values.size
    unless expected.eql?(provided)
      raise "wrong number of bind variables (#{provided} for #{expected}) in: #{statement}"
    end
    bound = values.dup
    statement.gsub("?") { bound.shift }
  end
end

As you can see, if you do not provide the right number of values for the statement, it will raise and error. Here is how you would use it:

puts ["Hello ?, how are you", "John"].merge
#=> Hello John, how are you

Likewise, you can use variables to hold values:

message = "Hello ?, how are you"
name = "John"
puts [message, name].merge
#=> Hello John, how are you

This will also work with multiple values:

puts ["Hello ?, ? and ?, how are you", "John", "Joe", "Jim"].merge
#=> Hello John, Joe, and Jim, how are you

The only downside to this currently is that you cannot use a ? in the string you are merging, as it will think its a binding character.

NoMethodError on nil.each?

Have you ever have to iterate over an array from say the params hash? You probably have added some code to make sure that data exists in the hash element first before doing the loop. This is a cool little trick to help condense some code. Normally I would write this:

if params[:accounts] and params[:accounts].size > 0
  params[:accounts].each do |account|
    # Do something with account here
  end
end

As you can see, kind of ugly. Here is the change:

(params[:accounts] || []).each do |account|
  # Do something with account
end

AHH!!! Much nicer!

Moving files in Rails using String

Since ruby allow for really easy overriding of objects and classes, I decided to make it easier and cleaner to move my files. Here is how you currently do it:

FileUtils.move("/path/to/file", "/path/to/new/file")

I know this isn’t a huge deal, but I would like to clean it up a little bit. I used an initializer (RAILS_ROOT/config/initializers/core_extensions.rb) to override the String class as such:

class String
  def move(to = nil)
    if to && File.exist?(self)
      FileUtils.move(self, to)
    end
  end
end

This allows me to do the following to move files:

"/path/to/file".move("/path/to/new/file")

I though it was pretty cool!

Easy Hash to XML and back conversion in Ruby

Instead of spending hours trying to write something custom to convert your hash into xml or vice versa, you can do it in one line. If you are already in a Rails environment, you are good to go, but if using ruby, include the ActiveSupport gem:

require 'rubygems'
require 'active_support'

Now that you have, we can convert a xml to a hash:

hash = Hash.from_xml(xml_stream)

And a hash to xml is stupid simple:

xml = hash.to_xml

There you have it, simple xml to hash and hash to xml!

%d bloggers like this: