Dec 16

EventMachine Asynchronous HTTP Client – Custom Headers (User-Agent)

Category: Development,Rails

If you have a need to set custom request headers like User-Agent or Host, here is how you do so via the EM client

http = EventMachine::HttpRequest.new(url)
  .get(:head => {"User-Agent" => "Custom Agent"})
No comments

Dec 9

iPhone 3g Jailbreak 4.2.1 SpringBoard crash and Linux mount

Category: iPhone,Linux,Ubuntu

After updating to 4.2.1 and untethered jailbreak via redsn0w on my iPhone 3g, I had two major issues. The first issue has to do with multitasking. The springboard would crash when using the fast switching. This was fixed by changing the following lines in /System/Library/CoreServices/SpringBoard.app/N82AP.plist

<key>opengles-1</key>

to

<key>opengles-2</key>

The next problem was mounting my iPhone in Ubuntu Linux. The error message will contain something about a timeout. If this is happening you probably need to re-pair the device by doing the following via the libimobledevice utils:

idevicepair unpair
idevicepair pair
idevicepair validate
10 comments

Dec 6

Apache Phusion Passenger: Apache 2 not found

Category: Development,Linux,Rails

This may be pretty basic, but figured it may be useful to others. According to the passenger docs, it will look for Apache in the $PATH environment variable. So to fix the Apache 2 not found error, you first need to find the install location. A very helpful command is “whereis” that comes standard on most *NIX systems. If you have whereis installed copy/paste the following into the command line

APACHE_PATH=`whereis apache | awk '{ print $2 }'`

That will set APACHE_PATH to the path returned from whereis. Before you continue, please make sure the path was set properly.

echo $APACHE_PATH

If everything looks good, update the $PATH environment variable.

export PATH=$APACHE_PATH/bin:$PATH

Then check path to ensure it was updated

echo $PATH
No comments

Nov 12

Ruby 1.9 CSV undefined method map for String

Category: Development

I’m in the process of upgrading an app running Ruby EE 1.8.7 to Ruby 1.9.2. Since FasterCSV is no longer available, I had to convert the code to use the internal CSV lib.  In doing so, I ran into the above error.  Looking at the source for FasterCSV <<, there was a catchall else statement that would handle passing a string and convert it to an array to become a row.

    def <<(arg)
      if arg.is_a?(Array) and arg.size == 2  # appending a header and name
        @row << arg
      elsif arg.is_a?(Hash)                  # append header and name pairs
        arg.each { |pair| @row << pair }
      else                                   # append field value
        @row << [nil, arg]
      end
 
      self  # for chaining
    end

In Ruby 1.9 the CSV << method is expecting an Array or CSV::Row. Easiest fix for me as to just make my string an Array. Hope this helps!

1 comment

Nov 5

Ubuntu 10.10 Thunderbird 3.1.6 LastPass addon disables password manager

Category: Linux,Ubuntu

In my quest to find a good password solution, I tried LastPass. This was a very intrusive password manager on both Firefox and Thunderbird. I promptly removed it after about a day of use. However, removal of the addon left traces of itself throughout my settings. It completely disabled Thunderbird’s integrated password manager. I was lucky enough to find an article at mozillaZine with details on how to re-enable this feature.

Here are the details from their site:

No checkbox to remember passwords

It can happen that you will find no checkbox in Thunderbird to remember passwords. To change this, you will need to edit the prefs.js file, located in the Thunderbird profile folder.

1. Close Thunderbird and open the prefs.js file in Notepad or another editor (make a backup copy of prefs.js first, as a precaution).
2. Find the following line: user_pref(“signon.rememberSignons”, false);
3. Change the value from false to true.
4. Close the Notepad or editor window and save changes.
5. On the next startup of Thunderbird you should find the checkbox for remembering the password in the password manager.

Instead of editing prefs.js, you can change the same setting via about:config.

While editing prefs.js, I found lots of settings that LastPass left behind. Also, in Firefox “about:config” shows the same situation. All in all, LastPass was a horrible solution. I changed to using FF and Thunderbirds built in password manager with a master password.

1 comment

Aug 3

Prototype JS default function arguments

Category: Development

$H() is just one more reason to use Prototype. Coming from a Ruby background, I’ve become very fond of using hashes. I often use them in handling optional arguments to methods, and setting default values for those arguments. I was creating a function in JS, and realized using such methodology would allow for a much more descriptive function.

function handle_notice(options) {
  var default_options = $H({show_notice: false, show_ignore: false})
  options = default_options.merge($H(options))
  ...
}

The above sets up a hash of default options, then merges or updates the default_options with the options hash passed to the function. This allows me to use any combination of arguments, or pass none to use the default.

1 comment

Apr 23

Handy ActiveRecord Migration Methods

We are undergoing a massive DB schema redesign. Much of the work is just tightening up the schema through optimizing indexes, setting default boolean and integer fields, and updating NULL allowed fields. Here is a little module I wrote to save massive amounts of code.

module MigrationHelper
  def index_exists?(table, lookup)
    lookup = Hash[:columns, Array(lookup)] unless lookup.is_a?(Hash)
    lookup.symbolize_keys!
    lookup.each{|key,value|lookup[key]=(value.is_a?(Array))?(value.collect{|v|v.to_s}):(value.to_s)}
    indexes(table).collect(&lookup.keys.first).include?(lookup.values.first)
  end
 
  def change_column_nulls(table_name, nullable, *column_names)
    column_names.each do |column_name|
      table_columns = columns(table_name) 
      column_def = table_columns.select{|c|c.name == column_name.to_s}
      raise "Unknown column name #{column_name} for #{table_name}\nAvailable columns: #{table_columns.collect(&:name).to_sentence}" if column_def.empty?
      change_column table_name, column_name, column_def.first.type, :null => nullable
    end
  end
 
  def change_column_defaults(table_name, default, *column_names)
    column_names.each do |column_name|
      change_column_default table_name, column_name, default
    end
  end
end

I fond it necessary to have the index_exists? method mainly for my development purposes. When I’m optimizing tables by doing complex indexes, I often do them right on the DB first before throwing them into a migration. By having this check I can easily skip over it if it already exists. It takes the same options as add_index. You can pass table and column names, or just table and index name. Here are some usage examples:

add_index :table, :column unless index_exists?(:table, :column)
add_index :table, [:column1, :column2] unless index_exists?(:table, [:column1, :column2])
add_index :table, [:column1, :column2, :column3], :name => "some_index_name" unless index_exists?(:table, :name => "some_index_name")

The method change_column_nulls is used to mass change the NULL allowed columns for a given table. Really not much to it, but saves a lot of code over doing change_table or change_column. Here is the usage:

change_column_nulls :table, false, :column1, :column2

And lastly change_column_defaults is just a wrapper around change_column_default for mass assignment. Usage is the same as change_column_nulls passing the default values as the second argument. I thought about combining the two, but it didn’t offer very much savings.

These were tested using MySql 5. I’m not sure about the compatibility with other servers.

No comments

Mar 26

Rails ActiveRecord MySql varbinary

Category: Development,Rails

Although ActiveRecord has the following warning about database specific column types: “You may use a type not in this list as long as it is supported by your database (for example, “polygon” in MySQL), but this will not be database agnostic and should usually be avoided. ActiveRecord” You may have optimizations specific to a database server like MySql’s varbinary. Here is how to create the a table with a varbinary(1000) column.

create_table :page_error_sources do |t|
  t.column :source, 'varbinary(1000)', :null => false
  t.timestamps
end
No comments

Mar 3

Solr 1.4 Upgrade P2 – Out with Rsync CollectionDistribution in with JavaReplication

Category: Development,Linux

Solr 1.4 made replication from Master to Slave servers a whole lot easier.  Before solr1.4 we were using rsync via the snapshooter and snappuller scripts As seen here.  This method worked OK, but intermittently we would see the snapshooter or puller fail for various Java reasons (Memory usually).

Please see Solr Java-Based Replication for setup overview.  I will cover specific modification I had to make compared to what is in their documentation.  In my solrconfig.xml on my Master server, I have the following:

<requestHandler name="/replication" class="solr.ReplicationHandler" >
      <lst name="master">
          <!--Replicate on 'startup' and 'commit'. 'optimize' is also a valid value for replicateAfter. -->
          <str name="replicateAfter">startup</str>
          <str name="replicateAfter">commit</str>
      </lst>
  </requestHandler>

Then on the slave servers, I have:

<requestHandler name="/replication" class="solr.ReplicationHandler" >
      <lst name="slave">
          <!--fully qualified url for the replication handler of master . It is possible to pass on this as a request param for the fetchindex command-->
          <str name="masterUrl">http://{solr_host}:{solr_port}/solr/${solr.core.name}/replication</str>
          <!--Interval in which the slave should poll master .Format is HH:mm:ss . If this is absent slave does not poll automatically. 
           But a fetchindex can be triggered from the admin or the http API -->
          <str name="pollInterval">00:00:30</str>
          <str name="httpReadTimeout">10000</str>-->
       </lst>
  </requestHandler>

Substitute {solr_host} and {solr_port} with your specific settings. IMPORTANT: Note the ${solr.core.name} variable.  This makes it so the slaves will poll from the correct MultiCore path on the Master server.

3 comments

Feb 1

Solr 1.4 Upgrade – Out with Faceting, In with MultiCore

Category: Development

I finally found some time, though it was a bit forced, to look into the new CoreAdmin functionality released in Solr 1.4.  Our app was using the same index for multiple apps distinguished through Faceting.  This worked fine for a while, but the larger our indexed data got, the slower the queries were returned.  The responsiveness of every app was now dependent on the total indexed size.  This was not ideal, so we upgraded to 1.4 to see how using multiple cores could help.

Upgrading was quite easy.  See http://wiki.apache.org/solr/Solr1.4 for upgrading notes.  What I will focus on are the details of using and automating the MultiCore functionality.  To enable the dynamic SolrCore functionality, you just need to put the following XML in solr.xml inside your solr_home directory.

<solr persistent="true" sharedLib="lib">
 <cores adminPath="/admin/cores">
 </cores>
</solr>

Don’t worry about creating any cores at this time.  The next thing I did was create a directory called “default” in my solr_home directory to store all of my shared configs for each core.  I then copied the conf/ directory from my solr_home into the newly created default dir.

The final step is to create the cores needed.  You can automate this by posting the following request and checking the XML response, or by just pasting this into your browser.

http://{host}:{port}/{solr_home}/admin/cores?action=CREATE&name={core_name}&instanceDir=default&dataDir={/full/path/to/solr/home}/{core_name}

Here is how you automate the request using xml-simple and ruby

#set the url string equal to the above command
response = Net::HTTP.get_response(URI.parse(url)).body
xml = XmlSimple.xml_in(response, {'VarAttr' => 'name', 'ContentKey' => '-content', 'KeyAttr' => 'name'})
raise "Failed to create solr core" if xml["lst"]["responseHeader"]["int"]["status"].to_i != 0

Master Solr server after upgrade to 1.4 and multi-core


Solr slave server after upgrade to 1.4 and multi-core

No comments

Next Page »