Thursday, April 7, 2011

jquery w/ rails : ajax update of drag & drop item

A script added to my html.erb file, at page load it establishes sortable columns, and ajax call to automatically update an item when it is dragged from one column to another:

$(function() {
$(".sortcol").sortable({
connectWith: ".sortcol",
receive: function(event, ui) {
$.ajax({
url: "<%= drop_url() %>",
type: 'PUT',
data: $.param({id : ui.item.attr('id'), state : ui.item.parent().attr('id')}),
success: function(d) { ui.item.effect("pulsate", {} , 500 ) }
})//end get
} //end receive function
}); //end sortable
}); // end function



The drop_url references as routes.rb entry /board/drop to a specific board_controller method. Upon retrospect, I'm thinking this ought to work with the default update method on my :story resource. Note to self, if your update method doesn't update... check that you haven't forgotten your parameter naming conventions. status != state no matter how you write the method to update.

Saturday, April 2, 2011

Rails -migrations with column default changes

So wanted to add a default value for a column, but also wanted to do a proper rollback method on the migration. My problem may have been more with SQLite than rails, something about it not liking alter column commands.

Anyway:
change_column :table, :column, :type, default = 'value' did update the schema.

But also needed to add the date
Table.update_all( "column = 'value'", "column IS NULL") to fix unset values.


Didn't find a good syntax to remove the default setting from the schema.

Saturday, March 12, 2011

Rails - Ruby: lesson in MVC

So turns out if you apply MVC correctly you save yourself from lots of unnecessary objects!

Originally I thought I needed a Board --> Panel --> Story. But as mentioned last post, using poro instead of ActiveRecord was getting 'interesting', as I had decided I didn't need any state for Board and Panel. As I was fixing tests... suddenly realized how all this was very unnecessary work:

The better solution is to create a BoardController, and then define the panels as simple attributes of that controller that reference the appropriate collection of stories:

class BoardController < ApplicationController
 def show
  @backlog = Story.find :all, :conditions => 'state IS NULL'
   respond_to do |format|
    format.html # show.html.erb
    format.xml { render :xml => @stories }
    end
  end
end

Now instead of needing to keep a bunch of keys, names in alignment between the view, board, panel objects... I just have simple associations. Each named collection I want is an attribute in the board controller, available to the view. The view simply needs to render each attribute appropriately. This approach also seem to have simplified my views, since now I just have the 'board' view, and a '_story' partial view to render each collection element.

Ruby-Rails : lessons on rails ActiveRecord vs plain old rails objects

Got distracted from doing the Agile-Web-Development-With-Rails examples, am now starting from scratch on an experiment with jquery and rails. I'm looking to see what I can achieve from a robust client app with rails based data & services via ajax.

1) Unit Tests throwing " ActiveRecord::StatementInvalid: Could not find table 'panels' "

Kept seeing this error for several basic assert statements in the model unit tests.
> assert p.is_a(Panel)
> assert p.display_text == 'backlog'

Noob mistake here... using 'rails g model' for objects that will not be stored in the database. Caused the objects to inherit from ActiveRecord class, and when ActiveRecord triggers automagic that expects a table to exist for the Panel class, and complains when it doesn't.

Instead, I really wanted to be dealing with plain old ruby objects, and viola! once I deleted the ActiveRecord reference in the model object.

> couldn't use is_a, instead had to use ruby method is_a?
> have to define the accessor methods for private instance variables.

Monday, February 7, 2011

Rails - Task I: Logging In - Noob notes on authlogic

There's a little auto-magic going on that as a rails/ruby noob I didn't expect.

1) The password, password_confirmation fields are not explicitly declared anywhere except for your registration, login views. This mean you have to add the "acts_as_authentic" to your User class BEFORE you can being using these fields in your views and tests.

2) Naming of your DB fields is important, password_confirmation != confirm_password. (Coming from a Java background, this feels weird, not having name control over model fields. Just go with it.)

3) After you do add acts_as_authentic, you have to update user_controller_test. Passing user.parameters doesn't work anymore, since that's the DB model and not what the user will send -- example of the changes that worked for me.

test "should create user" do
assert_difference('User.count') do
post :create, :user => {:email => 'test@functional.com', :password => 'godpassword', :password_confirmation => 'godpassword'}
end


4) Really enjoying the automated testing, they have been catching all kinds of mistakes I make in ignorance, and a great teaching tool. Am beginning to see how much you can skip explicit tutorials and APIs if the testing is robust.

Sunday, February 6, 2011

Rails - Task I: Logging In w/ authlogic_example

Picking up on a new branch, and take a few integration shortcuts to get authlogic up and running.

> git pull git://github.com/trevmex/authlogic_rails3_example

Then working through the merges necessary to merge in authlogic code, with a few skips
* git checkout --ours db/schema.rb
* git checkout --ours db/seeds.rb
* git checkout --theirs Gemfile
* change config/initializers/rspec_generator.rb Replace AuthlogicRails3Example with Depot (or your app name)

Then after code looked reasonably merged

> bundle install
> rake

Get complaints about unknown email_format validator

Seemed to have missed an important set of entries in config/application.rb

#Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += %W(#{config.root}/lib/**/)


This is required to reference the format validator introduced with the AuthLogic Example.

After this fix we get to something interesting... the rspec tests fail!

Rails - Task I: Logging In

For this task I decided to diverge from the book. From what I've heard attending Atlanta's local chapter meetings for OWASP (www.owasp.org), own-rolled authentication is at the root of far too many security flaws and breeches in web applications. Granted this book touches on some of the oft overlooked necessities (e.g. salted hash passwords), but for a real live website, I always push to use a robust, tested, peer-reviewed plugin over hand rolled code. At the very least, typical project timelines leave little time for developers and testers to stay current on the ever evolving threat landscape. If your shop is different, please, please help out the rest of us.

I looked around a bit and decided to go with authlogic. Trevmex has provided a fully Rails3 ready example found at https://github.com/trevmex/authlogic_rails3_example . http://www.dixis.com/?p=352 rewrites the tutorial for a few other steps you need to then incorporate the module into the depot code. (I did start first trying more commonly referenced authlogic_example by binarylogic at https://github.com/binarylogic/authlogic_example, but all I succeeded at was proving what I complete noob I am)

What follows is a combination of various sources. Comments indicate what prompted each step to be taken, but not the rationale or theory behind it.

Pre-Iteration Work: Adding authlogic to depot
$ sudo gem install authlogic #binarylogic

To depot Gemfile add:
# Add support for Authlogic authentication
gem 'authlogic', :git => 'git://github.com/odorcicd/authlogic.git', :branch => 'rails3' #trevmex
gem "rails3-generators" #dixis
> bundle install #'cause rake prompted me to run this after the changes.

> rails generate authlogic:session UserSession #dixis

>rake test

And viola! everything now fails because of 'ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: user_sessions: DELETE FROM "user_sessions" WHERE 1=1'

bummer!