Tuesday, March 03, 2009

Ruby Net-SSH connection with just a password

I've been trying to use Net-SSH for Ruby on Windows for little while but I couldn't easily find anything useful for my specific usage needs. What I want to do is to connect to a server using just a password and no keys. I found the information over here. http://net-ssh.rubyforge.org/ssh/v1/chapter-2.html. The tutorials out there showing password based connection didn't work for me because the behavior I was seeing (at least on Windows) was that net-ssh was looking for a key file even when I didn't want to use one. Of course using a dss based key file didn't work for me either so I'm set on connecting using just a password. So here's what worked for me.


Net::SSH.start( 'host', 'user',
:password => 'passwd', :auth_methods => ["password"]) do |session|
session.exec("ls -l")
end


From the documentation on the page mentioned above.. (These are also the only authorization methods that are supported.) If you want them to be tried in a different order, or if you don’t want certain methods to be used, you can specify your own list via this option.. Apparently the other methods would not fail-over to password based auth and just die on key auth. Specifying password authorization as the only method to try worked great for me. Keep in mind, this is only something I've observed on my Windows system so this might be a non-issue for a lot of you. If you are stuck on this like I was, I hope this was useful.

Wednesday, August 20, 2008

Sanitize_sql_array

The current Rails app I'm working on requires a custom sql in some sections, but writing out query conditions can be hassle sometimes. Using plain old ActiveRecord queries lets you put in conditions in the form of an array consisting of a simple query string containing question marks which are filled in by the parameter which follow the query string in this conditions array.

Example:
:conditions => [" foo = ? AND bar = ? AND baz IN (?)",
single_value_1, single_value_2, array_of_values ]

To use this conditions array for my find_by_sql queries I do this.

conditions_array = [" foo = ? AND bar = ? AND baz IN (?)",
single_value_1, single_value_2, array_of_values ]
condition_string = ActiveRecord::Base.send(
"sanitize_sql_array", conditions_array)

Now I have nice condition_string I'm able to use in my custom queries. I'm not all that experienced with Ruby's handling of scope, so I'm using the send method to access this protected class method. Let me know if there's a nicer way to do this.

Saturday, April 19, 2008

ActiveRecord raw insert/update

Sometimes, usually for performance reasons, it might be necessary to do raw SQL statements. Most of the time save_without_transactions is all you might need. But, if you still want to explicitly call an insert or an update for whatever reason, you're able to use the model connection's execute function. However, using (ActiveRecord)AR I've gotten quite lazy with writing queries. Here's something quick dirty I whipped up to generate queries.

class ActiveRecord::Base
def return_value_string(value)
case value.class.to_s
when "Time": "'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
when "NilClass": "NULL"
when "Fixnum": value
when "String": "'#{value.escape_single_quotes}'"
when "FalseClass": '0'
when "TrueClass": '1'
else "'#{value}'"
end
end

def generate_update_query
"UPDATE #{self.class.table_name} SET " +
self.attributes.keys.sort.collect{ |key|
"`#{key}` = #{return_value_string(self.send(key))}" }.join(", ") +
" WHERE id = #{self.id}"
end

def generate_insert_query
@key_vals = self.attributes.collect{ |key,value|
[key, return_value_string(value)] }
"INSERT INTO #{self.class.table_name} " +
"( #{@key_vals.collect{ |item| item[0].to_s }.join(", ") } ) " +
"VALUES( #{@key_vals.collect{ |item| item[1].to_s }.join(", ") } ) "
end

def raw_update
self.class.connection.execute(self.generate_update_query)
end

def raw_insert
self.class.connection.execute(self.generate_insert_query)
end

end


Now I can just do object.raw_insert or object.raw_update. I tried cover most of the data types I can think of in the 'return_value_string' function (I'm working with MySQL), but let me know of anything I might have missed. Another thing to play with is connection.insert and connection.update. I believe connection.insert can return the id of the row you just created so that might some slight bit of overhead that can be avoided. Doing queries this way might be better suited for data migrations rather than normal application requests. There's still the option of tracing through AR and see how it generates queries but this works well enough for now. As always, feedback is welcome.

UPDATE:
here is the revamped version for raw_insert and raw_update ripped directly from activerecord source. now you can get the id back on your inserts too. yay!

def raw_update
quoted_attributes = attributes_with_quotes(false)
return 0 if quoted_attributes.empty?
connection.update(
"UPDATE #{self.class.table_name} " +
"SET #{quoted_comma_pair_list(connection, quoted_attributes)} " +
"WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
"#{self.class.name} Update"
)
end

def raw_insert
if self.id.nil? && self.class.connection.prefetch_primary_key?(self.class.table_name)
self.id = self.class.connection.next_sequence_value(self.class.sequence_name)
end

quoted_attributes = attributes_with_quotes

statement = if quoted_attributes.empty?
self.class.connection.empty_insert_statement(self.class.table_name)
else
"INSERT INTO #{self.class.table_name} " +
"(#{quoted_column_names.join(', ')}) " +
"VALUES(#{quoted_attributes.values.join(', ')})"
end

self.id = self.class.connection.insert(statement, "#{self.class.name} Create",
self.class.primary_key, self.id, self.class.sequence_name)

@new_record = false
id
end

Monday, April 14, 2008

ActiveRecord sans transactions

So we're doing this massive migration from this legacy schema for a client, but our estimates put our import time at around 75 hours. So I thought transactions should help out but there was a problem. I'd wrap my insert/update loops with ModelClass.connection.(begin / commit)_db_transaction, but I noticed that every save call would automatically do BEGIN and COMMIT. After digging around for turning off this behavior at the connection level and getting nowhere, I saw method on my object. The function "save_without_transactions" was exactly what I was looking for. Of course there wasn't much documentation that I could find on this function. This might be useful to some newbies going through similar ActiveRecord issues as myself. This function also comes with the exclamation flavor that throws up an Exception. Hope this was helpful to someone looking to use ActiveRecord without transactions.

Saturday, March 22, 2008

And the winner is...

I've run ab on the current rails project at work using Apache and Nginx as the proxy frontend to a mongrel cluster. On average I've seen about a 10% increase in performance using Nginx (ymmv). There's plenty of easy mongrel configurations for Nginx that you can find online. Working with Fedora, made this extra simple. Yum install, configure, chkconfig to turn on nginx, chkconfig to turn off apache if you already have that on. More fun to explore is how it does with cached static content.

Tuesday, August 28, 2007

Rails: calendar_field helper

Yet another long overdue update. I'm currently working at a fun company where I've been doing some Ruby on Rails applications. We've settled on the javascript calendar from Dynarch for date fields in our projects. Of course, there's a bit of tedium involved with setting up the calendar for each field you want to use it in. Hooray for Rails.. my very first helper method eases some of this tedium. Just copy the two following functions into your application_helper.rb


def calendar_field(object_name, method, options = {})
object = instance_variable_get("@#{object_name}")
field_value = object.send(method) ? object.send(method).strftime("%m/%d/%Y") : ''
output = text_field object_name , method , :value => field_value
output += calendar_helper(object_name + "_" + method)
output
end

def calendar_helper(field_id)
'<script type="text/javascript">
Calendar.setup({
inputField : "'+ field_id + '", // id of the input field
ifFormat : "%m/%d/%Y", // format of the input field
showsTime : false,
timeFormat : "24",
singleClick : true
});
</script>'
end


and call it in your views like so


<%= calendar_field 'object', 'method' %>


Sure, you can combine both functions into one and add a date format as a param but so far this serves my quick and dirty needs.

Monday, September 04, 2006

Beginning with Xoops

So I just recently finished a contract job where they wanted a whole portal type deal with wiki, blog, forum etc. And they wanted all of this managed under centralized login ala CMS. After some digging, I landed on the Xoops page. This is a real neat project which makes it possible to integrate other php web apps such as mediawiki, wordpress etc. Some of the software I wanted to try out would only work well with xoops-2.2.3a-Final. Here's some little tweaks I had to do along the way to make things work just right.

Mediawiki in the xoops environment does lock out anonymous users from making edits, however you can't seem to restrict edit access to any particular user group(s) from xoops.

This little workaround did it for me. Mind you there's probably a nicer way to do it but the quick and dirty method worked for me.
In mediawiki/includes/User.php I modified the isAllowed function (which seems to get run on every page load) as such.

function isAllowed($action='') {
if ( $action === '' )
// In the spirit of DWIM
return true;

$this->loadFromDatabase();
global $xoopsUser;
ini_set("register_globals", "on");
#checking for edit page, edit action and whether user is logged in
if( ($_GET['action'] == "edit") && ($action == "edit") && ($this->mId) && is_object($xoopsUser) )
{
$usergroups =
$xoopsUser->getGroups();
#check if admin or a developer
if( in_array( 1 , $usergroups ) || in_array( 4 , $usergroups ) ){
return true;
}
else{
#deny edit access
return false;
}

}
else{
return in_array( $action , $this->mRights );
}
}
`

All I do right now is check for the usergroup ID's I'm interested in that big if statement but ideally you can build your array of ID's that you want to give access to and compare against. This is an exercise I leave upto you.

Another module that needed some work was the Edito module. This provides a nice and neat way to post static content on the site. There's even hooks to use an HTML editor. However this module didn't seem to even get to the install part right (I'm doing this on a Linux machine, not sure what the behavior is on Windows). The best thing to do before doing the install is turn on the debug mode in xoops. Right away I noticed that permission problems were keeping me from loading the module.
Moving on ..
In edito/admin/index.php
I changed.
include_once ("../include/nav.php");
include_once("../include/myblockslist.php");
to...
include_once ("../../include/nav.php");
include_once("../../include/myblockslist.php

Hope this was actually helpfull to someone. Let me know what you guys think.