Thursday, 28 May 2015

[SOLVED] jQuery not working in Rails until page reload

Let's picture this, you have started making a Rails application and you're excited to use JavaScript/jQuery in it, but when you run the app your JavaScript only works if you have reloaded the page, and not if you're navigating to it from some other page in your app. A weird problem, you might as well say!

Rails is shipped with a gem called Turbolinks which prevents your browser from loading the whole page every time you send a request, making them faster. Here is how they describe the gem on their GitHub page:

"Turbolinks makes following links in your web application faster. Instead of letting the browser recompile the JavaScript and CSS between each page change, it keeps the current page instance alive and replaces only the body (or parts of) and the title in the head."

You might be asking, what all this has to do with your problem, I was just coming to that. Now in your rails app, when you navigate from other page to your target page, instead of reloading the JavaScript again, it maintains the instance from the earlier page, and that's the reason why it doesn't work unless you reload your target page.

There are many workarounds to this problem, but the tidiest way I have come across is to add a gem called jQuery Turbolinks. Just add this line to your Gemfile and run bundle update

gem 'jquery-turbolinks'

then in your application.js file, require this in this particular order

//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//
// ... your other scripts here ...
//
//= require turbolinks

Now all you need to do is to restart your rails server, and you're good to go! Happy hacking!

Tuesday, 19 May 2015

Writing better code with RuboCop

Ever felt the inertia when you shift from a programming language, which you have been using for quite a few years, to a completely new one? You have, haven't you? While that inertia is a broad topic, I'll be talking about a small part of it today, which is following the community guidelines for coding.

From what I have seen so far, Ruby has a gem of a community and it's not surprising that they have a gem for you to learn writing Ruby code in the community-accepted way.

Introducing, RuboCop, a static code analyzer for Ruby which not only enforces community guidelines for coding but also fixes some of the problems for you. As Officer Alex J. Murphy said, all role models are important and so is this. Now let's how we can install this gem in our project. Add this line in your Gemfile and run bundle install

gem 'rubocop', require: false

That's it, now you can check all the files in your project with this command

$ rubocop

You can also configure rubocop as per your liking, just create a file .rubocop.yml in the root of your project. Here's how you can include or exclude files

AllCops:
Include:
  - '**/Rakefile'
  - '**/config.ru' 
Exclude: 
  - 'db/**/*' 
  - 'config/**/*' 
  - 'script/**/*' 
  - !ruby/regexp /old_and_unused\.rb$/

Now you're all set to write better Ruby code. Happy coding!

Monday, 18 May 2015

Denying login to non-admin users using Omniauth

In my earlier posts we have learnt how to do a simple login with Omniauth and denying admin access to pages for non admin users. Today I will be talking about how you can allow only Admins to log into a system. We will be referring to and building up on the code from the posts "Simple Google Authentication using Omniauth & oauth2" and "before_filter in Rails".

Now open up your sessions controller and scroll down to the create action, all the magic we're about to do will be done there. Using the admin? method which we defined in ApplicationController (in "before_filter in Rails") we will check if the google account belongs to one of the admins, if not they would not be loggin in to the system.

def create
  auth = request.env["omniauth.auth"]

  if admin?
    user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
    session[:user_id] = user.id redirect_to root_url, :notice => "Signed in!"
  else
    redirect_to root_path, :notice=> "Unauthorized Access"
  end
end

and that's it! After modifying the create action, you have implemented login exclusively for admin users.

Sunday, 17 May 2015

Writing specs for OmniAuth using Rspec

Recently, I used omniauth to implement google login in my rails application. Integrating and getting omniauth to work is pretty easy, if you are facing problems with that, you can check out another blog post which talks about just that. Now that you have knowledge of how omniauth will work in your project, you might want to write some specs for the same!

Here is where it gets a little tricky, for you to write specs for omniauth you'll have to mock it and insert omniauth.hash in the request environment.

Open your rails_helper.rb and add the following code to it.

OmniAuth.config.test_mode = true
omniauth_hash = { 'provider' => 'google_oauth2',
                    'uid' => '12345',
                    'info' => {
                        'name' => 'Tony Stark',
                        'email' => 'tony@stark.com',
                        'nickname' => 'Iron Man'
                    },
                    'extra' => {'raw_info' =>
                                    { 'location' => 'New York',
                                      'gravatar_id' => '123456789'
                                    }
                    }
  }
OmniAuth.config.add_mock(:google_oauth2, omniauth_hash)

Now whenever you need the omniauth hash in your specs, all you need to do is to call this line of code. After that your spec might look like this

before do
  request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:google_oauth2]
end

it 'should redirect to admin user' do
  get :create, :provider => :google_oauth2
  expect(response).to redirect_to(User.last)
end

Thursday, 14 May 2015

Setting Environment Variables with Figaro

You might have read another post from me which talks about setting up environment variables in which we implemented our own solution for assigning the env variables. Even thouh it was a pretty neat solution, the problem I faced was, I had to restart the rails server every time I made changes to the yaml file.

For a quick recap, you may want to use environment variables to store your secret credentials so that when you check your source code to a public repository, let's say github, your credentials aren't made public.

Meet Figaro, a gem which neatly does the job for you. First you'll need to add this line to your Gemfile and then run bundle update.

gem "figaro"

All you need to do now is run this on terminal

$ figaro install

This will create a config/application.yml file and also add it to .gitignore. Now you can just open up the application.yml file and set your environment variables. If you have to set value for ENV['MY_SECRET_IDENTITY'], in the file you will write

MY_SECRET_IDENTITY: 'Batman'

That's all for today. Happy Coding!

Wednesday, 13 May 2015

before_filter in Rails

I was recently trying to find a way to deny access to the admin panel in my rails application for users who aren't admin. One way would have been to check the authorisation inline in every action but I was looking for something cleaner.

Meet the before_filter method which helps you keep your controller actions clean and makes it easy to move out the authorisation logic. Here is how it looks

before_filter :admin?

You can also specify if this authorisation check only applies to a certain action, or certain a group of actions of the controller.

before_filter :admin?, :only => :new

before_filter :admin?, :only => [:new, :show]

The conditions on this filter aren't just limited to only, you can also specify except conditions on a before_filter, here is how you'll do it.

before_filter :admin?, :except => :show

before_filter :admin?, :except => [:show, :index]

Now comes the part where you define this admin? method. You can define a helper method in your ApplicationController, and put all your authorisation logic into that. That's all you need to be able to play admin. Happy hacking.

Tuesday, 12 May 2015

Setting Environment Variables in your Rails Project

You must have come across situations when you have to include sensitive information in your source code, like usernames, passwords, secret keys, etc. If you haven't yet, you most probably will. The problem is, if you want to put your source code in a public repository, say github, you don't want people to learn about that sensitive information, so what would you do?

Here environment variables come into the play and this is how it looks

ENV['MY_SECRET_INFORMATION']

Usually you can set environment variables via terminal, and heroku also allows you to mention all the environment variables your project requires if you deploy your application there, and then there are gems which ease the process for you. I'll be taking a different approach today and not use a specific gem for the task because I like keeping the number of dependencies low.

So we'll create a my_env.yml file in /config/. In that file, say you want to set value for ENV['MY_SECRET_IDENTITY'], you'll have to write

MY_SECRET_IDENTITY: 'Batman'

Pretty simple, isn't it? All you need now is write a simple code for the application to understand that YAML file. Open up your application.rb and add this piece of code

config.assets.version = '1.0'
config.before_configuration do
  env_file = File.join(Rails.root, 'config', 'my_env.yml')
  YAML.load(File.open(env_file)).each do |key, value|
    ENV[key.to_s] = value
  end if File.exists?(env_file)
end

Now all your sensitive information can be provided by that single YAML file, just make sure to add this /config/local_env.yml to your .gitignore file, you don't want to check that in, after all you did all this hard work for something!

NOTE: You might also need to restart the server.