Archive

Posts Tagged ‘tricks’

my git prompt

May 26th, 2010 2 comments

After long playing around with my prompt I finally made it stable and thought it’s time to share :)

So edit your ~/.bashrc file and add following lines on the end:

shopt -s promptvars dotglob histappend no_empty_cmd_completion cdspell xpg_echo

function parse_git_dirty {
  echo -n $(git status 2>/dev/null | awk -v out=$1 -v std="dirty" '{ if ($0=="# Changes to be committed:") std = "uncommited"; last=$0 } END{ if(last!="" && last!="nothing to commit (working directory clean)") { if(out!="") print out; else print std } }')
}
function parse_git_branch {
  echo -n $(git branch --no-color 2>/dev/null | awk -v out=$1 '/^*/ { if(out=="") print $2; else print out}')
}
function parse_git_remote {
  echo -n $(git status 2>/dev/null | awk -v out=$1 '/# Your branch is / { if(out=="") print $5; else print out }')
}
export PS1='$(ppwd \l)\u@\h:\[33[33m\]\w\[33[0m\]$(parse_git_branch ":")\[33[36m\]$(parse_git_branch)\[33[0m\]$(parse_git_remote "(")\[33[35m\]$(parse_git_remote)\[33[0m\]$(parse_git_remote ")")\[33[0m\]$(parse_git_dirty  "[")\[33[31m\]$(parse_git_dirty )\[33[0m\]$(parse_git_dirty  "]")>'

I know it looks a bit complicated, unfortunately it is … this is wired bash rule that escape sequences are evaluated before evaluation of functions/variables evaluation.

Some examples of prompt using this script:

mpapis@papis:~/old_laptop/nicz-projects/content2:master> touch a
mpapis@papis:~/old_laptop/nicz-projects/content2:master[dirty]> git add .
mpapis@papis:~/old_laptop/nicz-projects/content2:master[uncommited]> git commit -m "added a file"
mpapis@papis:~/old_laptop/nicz-projects/content2:master(ahead)>git push origin master
mpapis@papis:~/old_laptop/nicz-projects/content2:master>

To make it more useful the prompt is also colored to distinguish between states of git repo.

For lazy users the script could be also replaced by very easy version, which prints git status before each prompt line (only where git is applicable):

export PS1='$(git status 2>/dev/null)\[33[0m\]\n$(ppwd \l)\u@\h:\[33[33m\]\w\[33[0m\]>'

Note: download the code from here http://niczsoft.com/files/2010/05/my-git-prompt.txt

Categories: Development, Linux Tags: , ,

Deep associations in rails activerecord

May 22nd, 2010 Comments off

Some time ago I wrote about complex associations, now time to add another method and corrections.

First the finder_by_sql, in that particular case It was necessary to add

:readonly => true

So the code looks now like this:

  has_many :roles, 
    :readonly => true, 
    :finder_sql => '
SELECT roles.name FROM roles
INNER JOIN responsibilities ON roles.id = responsibilities.role_id
INNER JOIN assigments ON responsibilities.group_id = assigments.group_id
WHERE assigments.user_id = #{id}
GROUP BY roles.id
  '

There is one realy big downside of using finder_sql – it does not work with find_by_… or named scopes, so this forced me to continue searching and this is the result:

  def roles
    Role.scoped(
     {
       :joins => { :responsibilities => { :group => { :assigments => :user } } },
       :conditions => {"users.id" => id},
       :group => "roles.id"
     }
   )
  end

and now I can write:

user.roles.by_name(:admin).count

where by_name is an named scope

  named_scope :by_name, lambda { |type| {:conditions => [ "roles.name = ", type.to_s ] } }

complex associations in rails activerecord

January 30th, 2010 1 comment

During playing with CanCan from ryanb show in last railscasts I did planned some models and find me in quite strange situation – I knew the connection, but I could not easily get the result.

My models look something like:

class User < ActiveRecord::Base
  has_many :assigments
  has_many :groups, :through => :assigments
end
class Assigment < ActiveRecord::Base
  belongs_to :user
  belongs_to :group
end
class Group < ActiveRecord::Base
  has_many :assigments
  has_many :users, :through => :assigments
  has_many :responsibilities
  has_many :roles, :through => :responsibilities
end
class Responsibility < ActiveRecord::Base
  belongs_to :role
  belongs_to :group
end
class Role < ActiveRecord::Base
  has_many :responsibilities
  has_many :groups, :through => :responsibilities
end

So my first try was to get roles through groups manually:

User.first.groups.map{|g| 
  g.roles
}.flatten.map{|r|
  r.name.to_sym
}.uniq

But this solution is waste of resources, for system with a lot of possible roles it might be very inefficient, it takes first all groups of user and then ittereting through them gets all it’s roles. it will generate a lot of database queries.
So after some searching I got following code:

User.first.roles.map{|r|r.name.to_sym}.uniq

To make it working I used one quite nice feature of Active record – :finder_sql – so in user.rb I have added following line:

has_many :roles, :finder_sql => 'SELECT r.* FROM users u LEFT JOIN assigments a ON u.id=a.user_id LEFT JOIN responsibilities res ON a.group_id=res.group_id LEFT JOIN roles r ON res.role_id=r.id'

This makes it possible to get all the roles for a user just in one call, everything calculated on database side. Unfortunately there is one down side of this – the SQL code might be not portable to other databases, so use it only when You are sure You will stick to one database.
There is also other way around, it allows to get the same data in two sql calls, without using SQL queries, just on pure ActiveRecord usage:

Responsibility.find_all_by_group_id(
  u.assigments(:select=>'assigments.group_id').map{|a|a.group_id},
  :select=>'roles.name',
  :joins=>:role
).map{|r| r.name.to_sym }.uniq

There are many ways to archive the same goal, knowing them is only an part – knowing how they work, makes us aware how to chose the path.

on 2009-01-31 13:15 added:
Another way going out of the Group class:

Group.find(
  :all,
  :select=>'roles.name',
  :joins=>[:users,:roles],
  :conditions=>{:users=>{:id=>1}}
).map{|g|g.name.to_sym}.uniq

Did You liked this post or maybe not, vote on it at dzone.