Monday, 20 May 2013

Mercury: The WYSIWYG html editor

I had this application where different users would want to edit custom html pages to be shown up in there web sites. Each user will have his own domain( all domains pointing to the same Rails application ) and the custom html page had to be loaded as per the current domain. To do this, in search of a WYSIWYG html editor which is easy to setup and simple to start off, I ended up in Mercury. Whats really nice was that Mercury also had a gem to be used for Rails developer and as I am one, I had no more hesitation in get started with mercury.

To get started off with mercury, add

[code language="ruby"]

gem 'mercury-rails'

[/code]

to the Gemfile and bundle it.

Run the rails generator for the mercury files.

[code language="ruby"]

rails g mercury:install

[/code]

A couple of questions will be posted. Press 'yes' to install the layout files.

Now checking out the directory structure,  you could see three additional files.

mercury.js and mercury.css in the js and stylesheets assets respectively. Also, a new layout file for the mercury editor, mercury.html.erb 

I did remove the mercury css file later on.

One thing that needs to be noticed here is that the mercury.js file is heavy and it woudn't be a good idea to load it in all the pages. We would want to load it in only the pages that needs to be edited. Checkout the mercury layout file and you can see that the mercury.js file is included.

[code language="ruby"]
<head>
<meta name="viewport" content="width=device-width, maximum-scale=1.0, initial-scale=1.0">
<%= csrf_meta_tags %>
<title>Mercury Editor</title>
<%= stylesheet_link_tag 'mercury' %>
<%= javascript_include_tag 'jquery-1.7', 'mercury' %>
</head>
[/code]

Now to prevent mercury.js from being loaded up in the pages, we could move all the other js files in our application to a separete directory and then require the directory in our application.js

My application.js will have,

[code language="ruby"]
//= require_tree ./main
[/code]

where main is the directory which has all the application specific javascript. (Probably could be a better name :) )

Now peep into the routes file, you could see this extra line,

[code language="ruby"]

mount Mercury::Engine => '/'

[/code]

What this line does is that it allows the html pages in your application to be edited. An extra '/editor'  will have to be added at the beginning of each url path to load the mercury editor for the page.

Consider you have the url 'localhost:3000/pages' , all you need to load it in the mercury layout is to change it to ''localhost:3000/editor/pages' . You have mercury loaded up to edit your page and can now see it in the mercury editor's layout.

Screenshot

However this isn't just enough to start editing the page. You need to specify editable regions in the page.
In pages.html.erb 

[code language="ruby"]
<div class="control-group">
<h3 class="section_header page-header">Pricing page</h3>
<div id="faq" class="mercury-region" data-type="editable" data-mercury="full">
<%= render :file => file_path(@domain 'faq') %>
</div>
</div>
[/code]

Consider this piece of code. A div with id="faq" is made editable with class="mercury-region" and attributes data-type="editable" and data-mercury="full".

Now you can see the editable region.

Screenshot-1

This following line in above piece of code

[code language="ruby"]
<%= render :file => file_path(@domain, 'faq') %>
[/code]

invokes a helper method and loads the already created sample faq template which can now be edited and saved for the particular domain. As simple as that.

Similarly you could edit more pages here. This is how the contacts page can be edited.

[code language="ruby"]
<div class="control-group">
<h3 class="section_header page-header">Contact page</h3>
<div id="contact" class="mercury-region" data-type="editable" data-mercury="full">
<%= render :file => file_path(@domain, 'contact') %>
</div>
</div>
[/code]

Also, you probably might want to change the save url of the mercury editor for the particular page. That is the controller action to which the mercury edited contents will be 'POST' or 'PUT' (depends on the configuration set in the mercury.html.erb)

To change the mercury save url for this particular page, I wrote the script in the erb file ( pages.html.erb )

[code language="ruby"]
<script>
$(window).on('mercury:ready', function () {
Mercury.saveUrl = "<%= pages_upload_admin_domain_path(@domain) %>";
});
</script>
[/code]

You might also want to change the page thats to be redirected to once we are done with editing using mercury. We could bind on mercury's save event to get this done.

[code language="ruby"]
$(window).bind('mercury:saved', function() {
$(window.location.replace('/admin/domain'));
});
[/code]

All this saved data would have to be dealt with in the controller action. Inspecting the params in the controller action ( the mercury Save url) ,
{"content"=>
{"faq"=>
{"type"=>"full",
"data"=>{},
"value"=> "<h1>This is where I have done my FAQ editing</h1>"
"snippets" => {}
}
},

{"contact"=>
{"type"=>"full",
"data"=>{},
"value"=> "<h1>This is where I have done my Contacts editing</h1>"
"snippets" => {}
}
}
}


There are two things of notice here. The contents hash contains all the mercury related stuff.  Each hash in the contents hash has a key which is equal to the id of the mercury editable html divisions ( see the view code pasted above ), here 'faq' and 'contact'. The actual edited html content can be found in the hash with key 'value' ( <h1>This is where I have done my Contacts editing</h1>).  'The controller action could decide on how to save this html content.

What have I done to solve my case mentioned at the starting?

I created a pages directory in my public. Within the pages directory I created sub directories which corresponds to the domain. For eg, the domain localhost corresponds to the directory named localhost inside the public/pages directory and the domain remotehost corresponds to the remotehost directory.

I then saved all these edited html content as html files within these domain specific directories. When a particular domain was loaded, the html pages ( for eg, faq and contact) was rendered from the corresponding domain directories in the public folder .

Sunday, 19 May 2013

Delayed Jobs in Rails: Adding custom attributes

Ok, so this was my exact scenario. When I was doing a bulk emailing application,  there was the need for the client to upload his set of email ids as a file and then save it to the database. The process of saving these contact mail_ids for a particular mail group was a delayed process, handled by Rails delayed job . 


[code language="ruby"]
@mail_group.delay.save_group_contacts
[/code]

where @mail_group is the active record group to which the mails_ids being uploaded and saved belong.

The requirement was to show a progress bar for the process of the mail_ids being saved to the the mail group. To handle this, I decided to add custom attributes to the delayed jobs table so as to identify the owner of the delayed job and also find the progress of the job.

To do this,

1) DB migration to add the custom attributes

[code language="ruby"]
class AddColumnToDelayedJob < ActiveRecord::Migration
def change
add_column :delayed_jobs, :job_process_status, :integer, :default => 0
add_column :delayed_jobs, :job_owner_id, :integer
add_column :delayed_jobs, :job_owner_type, :string
end
end
[/code]

2) A model for the delayed jobs table.

[code language="ruby"]
module Delayed
class Job < ActiveRecord::Base
self.table_name = "delayed_jobs"
attr_accessible :job_owner_id, :job_process_status, :job_owner_type
belongs_to :job_owner, :polymorphic => true
end
end
[/code]

As seen, three extra attributes (job_owner_id, job_owner_type attributes for establishing a polymorphic association with the job owner of the delayed job and a job_process_status attribute for updating the progress of the job) were added to the delayed jobs table.

Delayed jobs were then created with the job_owner_id and job_owner_type.

[code language="ruby"] @mail_group.delay(job_owner_id: @mail_group.id, job_owner_type: @mail_group.class.name).save_group_contacts[/code]

However this would not be enough to update the custom attributes. An attempt to create a delayed job would produce this

[code language="ruby"]
ActiveModel::MassAssignmentSecurity::Error:
Can't mass-assign protected attributes: job_owner_id, job_owner_type
[/code]

As a quick fix, add a config/initializers/delayed_job.rb
and paste in the following code

[code language="ruby"]
class Delayed::Job < ActiveRecord::Base
self.attr_protected if self.to_s == 'Delayed::Backend::ActiveRecord::Job'   #loads protected attributes for  # ActiveRecord instance
end
[/code]

Now the delayed job would get saved with the job_owner_id and job_owner_type.

Also, in the mail_group model, set an association to the delayed jobs table.

[code language="ruby"]
class MailGroup < ActiveRecord::Base
has_many :deferred_jobs, :as => :job_owner, :class_name => "::Delayed::Job"
end
[/code]

Now you can access all the delayed jobs of a particular @mail_group as

[code language="ruby"] @mail_group.deferred_jobs[/code]

The job process status which is updated by the running job can also be accessed as

[code language="ruby"] @mail_group.deferred_jobs.job_process_status[/code]

Sunday, 18 December 2011

Git Reset, Revert, Merge Conflicts and the Case Of The Faulty Merge

Git, as we know is a fast, open source, distributed version control system that is quickly replacing subversion in open source and corporate programming communities. As a developer, many a times i have been amazed by the power of git and how it takes care of our code repo. It track files in the project, we periodically commit the state of the project when we want a saved point. The history of our project is shared with other developers for collaboration, merge between their work and ours, and compare or revert to previous versions of the project or individual files.

As mentioned earlier, Git, at a fast pace, is replacing subversion in open source and corporate programming communities. Hence most open source developers would have had a taste of git and its power. We all would have done a git init, push, pull, rebase and stuff in our day to day programming activity and those would be quite trivial to most developers.

However there are certain facets of git(merges, conflicts, reverts and such) which does create some kind of confusion to developers, at least when they use it for the first time. What made me write down this post is an incident that happened to my colleague while he was on work. Will get into that shortly.  Before  getting into that, let me just stitch in a brief on Revert and Reset in git.

Revert and Reset

Git provides us multiple methods for fixing up mistakes while in development mode. This is important, because it saves not just our work but the others who are involved in the same project.

If you have actually done a mess with your working directory, but actually haven't committed the changes, the best way is to perhaps do a hard reset.

$ git reset --hard HEAD


This would just wipe off the changes that you have made in your git index and also any outstanding changes that you have made in your repo.

Now suppose you have committed your changes, but haven't pushed it into master,  and then suddenly you feel like you shoudn't have made the previous commit(or a sequence of your previous commits), you could again reset hard. This is as simple as doing

$ git reset --hard HEAD~n


This would set the HEAD of the git index to 'n' commits prior to your current head. The problem though with doing a git reset --hard is very obvious. This is how your commit log looks like with at A its head

o  ->  o  ->  o  ->  D  ->  C  ->  B  ->  A


Suppose you do

$ git reset --hard HEAD~3


Now your commit log would be.

o  ->  o  ->  o  ->  D


This means that the changes that you made right from A to C have been vanished and you are not going to get it back. The bottom line is simple. You are not able to change the effects made by a single commit(ofcourse, the exception is your last commit as we have already seen).

git-revert is just for that.

The current commit log would look like this

o  ->  o  ->  o  ->  D  ->  C  ->  B  ->  A


At any point of time, you realize that 'C' is bound to break your code(hopefully it still hasn't), you may well want to undo the changes made by C. This could be done by

$ git revert (commit id of C).


This would create a new commit that undoes the commit C. You will be given a chance to enter a new commit message, but the default message that indicates its 'the reverse of the commit C' would be the most indicative commit message to have.

o  ->  o  ->  o  ->  D  ->   ->  B  ->  A  ->  rC


where rC is the reverse of C.

This revert is a straightforward revert(i.e. it just undoes the data made by the commit reverted). Since all thats being talked about is a single branch, there aren't any complications that would arise here.

Merge and reverting a faulty merge

Now let me talk about the incident that i had mentioned earlier. All these happened as a result of an accidental Merge. My friend did this

$ git pull origin experimental


while he was still sitting in his master branch. The experimental branch has now been merged into the branch master. This was totally unintentional(he never planned to do a merge). There were no merge conflicts however. The mainline code broke. We had to revert this faulty merge.
Master  ->            P   ->   x    ->  M
                                \                     /
                                   \                /
Experimental ->        A    ->   B

This would give you a picture. P is the point of branching. x is some commit made in the mainline branch totally unrelated to the side line branch. The side line branch itself has got two commits of its own, A and B. M is the merge commit (experimental has been merged with master). The code broke. Hence, we need to revert M(the merge commit).
Master  ->            P   ->   x    ->  M  -> W
                                \                     /
                                   \                /
Experimental ->        A    ->   B

Now as seen, the merge has been reverted(W is the reverse of M). This was done with

$ git revert -m 1 (Commit id of M)


This adds W to the commit log as well. Now the faulty code in the experimental branch was worked upon and fixed and its been made ready for the merge (again!). The experimental branch is now merged with the master branch. What was weird(for us, at that point of time) and noticeable was that the code changes that were made after the 'merge revert' appeared in the master branch whereas the ones made before the revert didn't appear. i.e.

Master - >          P -> x -> M -> W -> x -> x -> M2

Experimental ->        A -> B  -  -  -  -  -  -  -   C -> D


Again, x are the commits unrelated to the experimental branch. M2 is the second merge. Commits in the experimental branch,C and D, fixes the faulty code in A and B. Whats to be noticed is that, after the updated experimental branch has been merged, none of the changes made by A and B would appear in the master branch, whereas the changes made in C and D would.The reason was found out soon.

Linus Torvalds explains the situation:

     Reverting a regular commit just effectively undoes what that commit
     did, and is fairly straightforward. But reverting a merge commit also
     undoes the _data_ that the commit changed, but it does absolutely
     nothing to the effects on _history_ that the merge had.

     So the merge will still exist, and it will still be seen as joining
     the two branches together, and future merges will see that merge as
     the last shared state - and the revert that reverted the merge brought
     in will not affect that at all.

Thats what just happened here. W(merge revert) undoes the data made by M(merge) but does nothing to the commit history brought in by M.There fore when the second merge,M2, is made, the commit history is checked and M is found to be 'last shared state'. Hence, only those changes that has been made after the 'last shared state', M, will be merged into the master branch now(i.e. commits C and D). None of the data created in A and B would merge, because as per the commit history, they are already merged.

Solution to this problem is also explained by Linus himself. The fix is to 'revert the revert that brought in W', i.e, revert W before you do in the next merge,M2.

Thus the main line commit log would be

P  ->  x  ->  M  ->  W  ->  x  ->  x  ->   ->  M2.


where Y is the reverse of W and M2 is the merge made after that.

$ git revert (commit id of W)


adds Y to the commit log. The above commit log would be equivalent to

P  ->  x  -> M  ->  x  ->  x  ->  M2


where there is no W nor a Y and then the second merge has been performed, M2. Now this would be fine, and all the changes made in the experimental branch should be seen in the master branch(ignoring merge conflicts). If there are any merge conflicts arising, git leaves the index and the working tree in a special state that gives us all the information needed to resolve the merge.

Merge Conflict

A Merge conflict would throw in the following message:
CONFLICT (content): Merge conflict in sample_script.rb Automatic merge failed; fix conflicts and then commit the result

Trying to switch to the experimental branch would give you this
error: you need to resolve your current index first

The files with conflicts will have markers upon them.
<<<<<<< HEAD:sample_script.rb "We would be starting off now" ======= "This would be the end" >>>>>>> d31f96832d54c2702914d4f605c1d641511fef13:sample_script.rb

Now we need to resolve these conflicts manually followed by adding the file and commit it.

$ git add sample_script.rb
$ git commit -a


The commit message would already be filled in indicating that its a conflict resolving commit. I always prefer not to add in anything extra on that.

gitk

It would also be helpful to have the 'gitk' tool when you are analyzing your commit logs, specially when you have more than once branch. You would be given a neat graphical representation of your working directory.

$ sudo apt-get install gitk


if you already don't have one.

Image

This definitely would be helpful in getting a better picture.

Tuesday, 12 July 2011

Solution to 'Wireless disabled by Hardware switch'

Ohhh ... Suddenly my wifi goes off( a combination of DELL with Ubuntu natty) and got a display - wireless disabled by hardware switch. Got down to googling and finally got this.

To get back your wifi to start working, type in the following:

$:  sudo rfkill list

You will get back something like this.

0: dell-wifi: Wireless LAN
    Soft blocked: yes
    Hard blocked: no
1: dell-bluetooth: Bluetooth
    Soft blocked: no
    Hard blocked: no
2: phy0: Wireless LAN
    Soft blocked: yes
    Hard blocked: no
4: hci0: Bluetooth
    Soft blocked: no
    Hard blocked: no

As you could see (0,2) the Wireless Lan has been soft blocked.  We need to unblock it to get it up and working properly.

$: sudo rfkill unblock 0

$: sudo rfkill unblock 2

 

Restart your networking

$: sudo /etc/init.d/networking restart

 

and yup! the wifi should be back now.

Monday, 4 July 2011

RubyconfIndia 2011

May 27,28 - Attended Rubyconf India 2011 held at Royal Orchid hotel, Bangalore.'  For some one who has less than a year of hands on with ruby, it was great hearing from the giants - the very Matz himself expressed his love for the community(in his own peculiar Japaneese way), Ola bini, Chad Fowler,  Brian and others. What in short ? - awesome 2 days.









Module functions as class and instance methods

Consider you have a module and a class.

module Mymod and a class Myclass.

The situation in hand is such that certain functions in the module need to end up being instance methods of the class Myclass and certain functions need to be Class methods.  You could very well imagine of such situations. Consider you are using ActiveRecord and have a sub class Subscription in correspondence with a DB table. You want to insert logic, within the module, that would work in each of the following case.

1) When a subscription fails or succeeds.

2) When an unsubscription fails or succeeds

You do this.

module SubscriptionLogic


   def  after_sub


      ....


   end


   def  after_unsub


     ....


   end


   def  after_sub_fail


     ....


   end


   def  after_unsub_fail


      ....


    end


end


class Subscription

   include SubscriptionLogic

   .....

end

You insert the logic as functions of a module, say SubscriptionLogic. Ideally you want the methods containing the logic to be instance methods of the class Subscription. You include the module SubscriptionLogic in the class and you avail all the functions in the module as Instance methods. Now you consider the case when an unsubscription fails - i.e, there is no existing subscription so that an unsub could take place.  No way is it possible that you could have a function 'logic_after_unsub_fail'  in the module SubscriptionLogic and use it as an instance method, simply because there is no instance available.  You think and decide to use the function as your class method, but you have 'included'  the  module in your class and hence its not possible to use it as your class method. You cannot extend the entire module coz , ideally you want the logic to be instance methods.

So you could get this solved up by a simple piece of extra coding.

module SubscriptionLogic

  def  after_sub

      ....

  end

  def  after_unsub

      ....

  end

  def  after_sub_fail

      ....

  end

  module ClassMethods

      def after_unsub_fail

           ....

      end

      def self.included(base)

          base.extend(ClassMethods)    # base pertains to the class within which you include the module.

      end

   end

end

Now within the class insert this line.

class Subscription

   include SubscriptionLogic

   extend SubscriptionLogic::ClassMethods

   .....

end

Sunday, 3 July 2011

Back after a Long Gap...

Haven't Written any thing for  quite some time now. It was last november that i actually sat down to write something. Started off my professional career then and obviously was busy with work and stuff. Need to get back to writing stuff, little and bigger stuffs that i have learnt while working. In between i have fallen in love with a a new language - Ruby, the popular choice for web apps these days.  From a person who never had any kind of fondness for OOP, i have started loving to talk about about objects and classes. Learnt the difference between fun coding and professional coding. These 6-8 months has really been a learning curve for me and i really do hope that my following posts would reflect that.