DRY your Rails Model

When you’re trying to make some controllers of your app tinier with agreement to have fatter models, you might think about scope or writing functions for that Model class. In this post, I wanna write some examples of that Active Record technique

Problem definition

The problem my rails app is about is:

    • We have models: User, Post and Tag
    • User and Post have 1-n relationship while Post and Tag have the n-n relationship
    • We gonna find Post with many constraints relating to User and Tag
    • For Post, we have state:string

Before DRY

In the Post model, we have state as and is in ['draft', 'published'] . It’s is normal to query posts by state like

published_posts = Post.where(state: 'published')
draft_posts = Post.where(state: 'draft')

How if you wanna check if a post published or not

post = Post.where(id: 1).first
is_published = post.state == 'published'

And now I wanna get posts of some authors

posts = Post.joins(:authors).where(author_id: params[:author_ids])

or posts with some tag names

posts = Post.joins(:tags).where(tags: {name: params[:tag][:names]})

With some improvements

All are good now, right? hm, it could be even better if we can give some logic to our model

Like this

class Post < ActiveRecord::Base
  STATES = ['published', 'draft']
  belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
  has_many :tags, through: :post_tags

  scope :published, where(state: 'published')
  scope :tag, lambda{|tags| joins(:tags).where(tags: {name: tags})}

  STATES.each do |state_name|
    define_method "#{state_name}?" do
      self.state == state_name
    end
  end
end

Then, we can have

posts = Post.tag(params[:tags]).published
post = Post .find(params[:id])
post.published?

Happy Coding!

Global method in Rails

If you are familiar with Devise, you might know very well what is current_user. Imagine now you have a several controllers which relate to another object model, example: Project instead of User, and you want to define current_project for your actions in different controllers? I think of a solution, that is to store current_project in cookies, we can get or set this value.

  • First, we should create a projects_controller:
class ProjectsController < ApplicationController
  def current_project
    return cookies[:current_project] ? cookies[:current_project] : Project.first 
  end

  # Set this method as helper method to be able to use in views
  helper_method :current_project
end
  • Then, in other controllers you can inherit that ProjectsController:
class Manager::ProjectsController < ProjectsController
end

class Developer::ProjectsController < ProjectsController
end
  • Or views:
<%= current_project %>
  • You can create an action to change it if necessary
def change_current_project
  cookies.permanent[:current_project] = params[:current_project]
  redirect_to request.referer || root_url
end

Have fun programming!

CoffeeScript: Set active class for element based on URL

Hi, today I find another useful snippet by CoffeeScript for your sites.

I have a left side bar which has a list of my objects. Each of them element on the sidebar contains a link redirecting to another object. I wanna to set active class based on URL after reloading the site.

And, below is my snippet.

Hope it useful!

ready = ->
  setActiveElement = () ->
    ## using js regular expression to get id
    element_id = document.URL.match(/(\w*\/)([0-9]+)/); 
    if element_id ## in case user view the element
      element_id = element_id[0]

      ## Get element on view which have a href contains element_id    
      element = $("li:has(a[href$='"+element_id+"'])");
      element.addClass('active');

  setActiveElement(); ## call on load

$(document).ready(ready)
$(document).on('page:load', ready) ## reload js even setting turbolink
window.ready = ready

Flush memcached in Rails console

Rails 4 is using Dalli memcached. You can check here

Sometimes you will need to flush all Dalli memcached in Rails, in order to refresh the page for new update. You have several methods. However, I think using Rails console is one of the straight way to do this. It is simple, and safe because you can check the right memcache server.

$ rails c -e ENVIRONMENT

## check the right Dalli memcached server
Rails.cache.dalli 

## => #86400, :compress=>true}, @ring=nil>

## Clear the cache
Rails.cache.clear

Support Multiple Screens for Web Application

There are so many reasons that you should not only create a responsive design, but also multiple designs for multiple screens including desktop, table, smartphones.

And this is an example how I make my website support multiple screen resolutions.

The first thing you need to do is add this line of code to head tag of html file. Or in application.html.erb in Rails app

<meta name="viewport" content="user-scalable=no, 
                      initial-scale=1.0, maximum-scale=1.0, width=device-width">

Now you need to create some lines of Javascript code:

function adjustStyle(width) {
    width = parseInt(width);
    if (width < 480) {         document.body.className = "smartphone";     } else if (width >= 480 && width < 800) {
        document.body.className = "tablet";
    } else {
        document.body.className = "desktop";
    }
}

$(function() {
    adjustStyle($(this).width());
    $(window).resize(function() {
        adjustStyle($(this).width());
    });
});

It is now CSS turn. I make an example with an id call #content

#content{
    float: left;
    position: relative;
    font-size: 14px;
    font-family: sans-serif
}

.desktop #content{
    width: 50%;
    margin-left: 25%;
    background-color: white;
    color: black;
}

.table #content,
.smartphone #content{
    width: 95%;
    margin-left: 5%;
    background-color: grey;
    color: white;
}

Enjoy 🙂

Download and Upload File to AWS S3 in Ruby

## Install gem aws-sdk first
require 'aws-sdk'
require "httparty"

ACCESS_KEY_ID = 'your access id to aws s3'
SECRETE_ACCESS_KEY = 'your secrete access key to aws s3'
BUCKET_NAME = 'Your aws s3 bucket name'

s3 = AWS::S3.new(access_key_id: ACCESS_KEY_ID, secret_access_key: SECRETE_ACCESS_KEY)

## Name of file name to store in your local
file_name = "#{Rails.root}/tmp/#{File.basename(User.first.avatar_url)}"

File.open(file_name, "wb") do |f|
  ## Write file to local
  f.write HTTParty.get(User.first.avatar_url).parsed_response

  key = User.first.avatar_url.match('file_url_domain').post_match
  s3.buckets[BUCKET_NAME].objects[key].write(:file => file_name)
end

Backup your Mysql database


It is not always that in a project you can use library as yaml_db or seed_fu. Sometimes you just want to move a database from this server to another server. And ofcourse, use mysqldump will be faster.

First, you my want to connect to remote server via ssh and private key:

sudo ssh -i path_to_your_key remote_user_name@remote_server_address

Dump database:

## Dump all tables of database
mysqldump -h database_host -u database_user_name -p database_name > my_db_dump.sql

## Dump some tables of database
mysqldump -h database_host -u database_user_name -p database_name table_1 table_2 table_3 > db_part_1_dump.sql

## Dump database ignore some
mysqldump -h database_host -u database_user_name -p database_name --ignore-table=my_database.table1 my_database.table2 > db_part_1_dump.sql

Restore database:

mysql -u db_user_name databse_name -p -h host_name < path_to_sql_dump_file

If you need to copy file from your remote server to local computer, use this

sudo scp -i path_to_private_ssh_key remote_user@remote_host:path_to_dump_db_file_on_remote path_to_where_you_want_to_store_on_local

## Or reverse way
sudo scp -i path_to_private_ssh_key path_to_where_you_want_to_store_on_local remote_user@remote_host:path_to_dump_db_file_on_remote 

Bootstrap Glyphicons in Rails

Recently, I have add bootstrap.min.css manually, not from gem. And I got error when trying to add Bootstrap glyphicons. I’m not sure using gem does get this error or not. However, This just a trick to add Bootstrap Glyphycons to Rails manully alongside.
The first thing you need to do is add @fontface in your bootstrap file:

@font-face {
    font-family: 'Glyphicons Halflings';

    src: url('/fonts/glyphicons-halflings-regular.eot');
    src: url('/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}

After that, in order to make these fonts works, I added bootstrap fonts folder to public folder

Finally, use it in you view file like this:

<span class="tag-item"><span class="glyphicon glyphicon-tag"></span> <a href="">Tag 1, </a></span>

Set Headers in Ajax Request

  ## I used Coffee Script syntax
  ## @ sign here to set this function available in .erb file

  @yourFunction = (auth_token) ->
    $.ajax({
      type: "GET",
      url: "/url/path",
      headers: { 'Authorization': 'Token token=' + auth_token }
    }).done((data) -> console.log(data)
    ).fail((jqXHR, textStatus, errorThrown) -> 
      console.log("Request failed: " + textStatus)
      console.log(errorThrown)
    });