RoR Restful Authentication
I got sick of forgetting what to google to find this so I am keeping my notes here.
./script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication
Then run
./script/generate authenticated user sessions
You can add --include-activation to have add more features but i havent used that yet…. It works great as is.
Re-compiling PHP 5 for OS X
This post is intended as a simple reminder for me to help me remember what I did when setting up a new PHP environment… help yourself to my notes, but you’re on your own if it breaks your server.
Here is a breakdown of what to install in what order… jpeg6, gd, libpng, mcrypt, mhash
Build the jpeg6 lib first- ftp://ftp.uu.net/graphics/jpeg/
I put the tar files in ~/_bin then I unpacked it with
tar -zxf [tarfile]
then moved the dir to /usr/local/php. Then CD into that dir and do the following:
cp /usr/share/libtool/config.sub .
cp /usr/share/libtool/config.guess .
./configure --enable-shared
make
sudo make install
Then you should recompile GD so it will see the new jpg6. Same thing, download GD to the ~/bin and untar it and move the dir to /usr/local/php.
./configure
You should see something like this:
Support for PNG library: yes
Support for JPEG library: yes
Support for Freetype 2.x library: yes
Support for Fontconfig library: yes
Support for Xpm library: yes
Support for pthreads: yes
Then do this:
makel
sudo make install
Now you will need libpng (http://www.libpng.org/pub/png/libpng.html). Untar it and move it to /usr/local/php
./configure
make
sudo make install
Now you need freetype and xpm… Im not going to try and figure out fonts so since fonts are already on the system you can use them this way in the config for php in just a few minutes.
–with-freetype-dir=/usr/X11R6 \
–with-xpm-dir=/usr/X11R6 \
Now for mcrypt and mhash. Go here and download the latest version of mcrypt ftp://mcrypt.hellug.gr/pub/crypto/mcrypt/libmcrypt/. Same as the others, untar them and move them to /usr/local/php. CD into that dir then
./configure
make
sudo make install
And finally mhash. Go here and download it. http://sourceforge.net/project/showfiles.php?group_id=4286. Again, untar it and move it to /usr/local/php then
./configure
make
sudo make install
Now you are finally ready to compile PHP.
./configure --with-prefix=/usr \
--with-mandir=/usr/share/man \
--with-infodir=/usr/share/info \
--with-disable-dependency-tracking \
--with-apxs2=/usr/sbin/apxs \
--with-ldap=/usr \
--with-kerberos=/usr \
--with-enable-cli \
--with-gd \
--with-freetype-dir=/usr/X11R6 \
--with-xpm-dir=/usr/X11R6 \
--with-png-dir=/usr/local/lib \
--with-jpeg-dir=/usr/local/bin \
--with-tiff-dir=/usr \
--with-zlib-dir=/usr \
--with-enable-trans-sid \
--with-xml \
--with-enable-exif \
--with-enable-ftp \
--with-enable-mbstring \
--with-enable-mbregex \
--with-enable-dbx \
--with-enable-dbase \
--with-enable-trans-sid \
--with-enable-sockets \
--with-enable-wddx \
--with-enable-bcmath \
--with-iodbc=/usr \
--with-curl=/usr \
--with-config-file-path=/etc \
--with-sysconfdir=/private/etc \
--with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-mysql=/usr/local/mysql \
--with-pdo_mysql=/usr/local/mysql \
--with-openssl \
--with-xmlrpc \
--with-xsl=/usr \
--with-mcal=/usr/local/php \
--with-mcrypt=/usr/local/lib \
--with-mhash=/usr/local/lib \
--with-mime-magic \
--with-pear
I was able to run make fine, but when running make test I got an error…. After alot of digging around, I found this helpful post at php.net.
“After screwing around for an hour and screaming many profanities at my computer I looked back at the error and noticed:
/usr/local/mysql/lib/<b>mysql/</b>libmysqlclient.15.dylib
Why it was using this path I do not know, but I headslapped when I realised how simple it was! I solved the problem by creating a link called mysql that linked back on itself:
cd /usr/local/mysql/lib
sudo ln -s ./ mysql
Problem solved! I probably should have figured out why it was doing this instead, but this was easier and saved me from allot more frustration.”
This worked for me as well.
Reindexing Ferret Part II
Automating the re-indexing process was a bit different than I thought it would be.
Yesterday I posted that you can use script/console. Which is true, but you cant run that in a cronjob. Or, at least I couldnt get it to run in a cronjob.
So I learned about script/runner. I used it like this… I put a .rb script in lib/task called ferret_index.rb.
class FerretIndex < ActiveRecord::Base
MyModel.rebuild_index
end
Then my cronjob
0 1 * * 7 /usr/local/bin/ruby /usr/local/apache2/htdocs/<my project>/script/runner /usr/local/apache2/<my project>/lib/task/ferret_index.rb
Every sunday at 1:00 am my index will be updated.
Reindexing Ferret
Its really simple, wished I had seen this part of the documentation a couple months ago.
Lesson learned. As the databse was being updated more often and becoming very large, indexing became more difficult to do just by doing a search in the browser. Back to the documentation and there it was.
script/console
>>MyModel.rebuild_index
Plus, the indexing seems to be much faster. Looking into running the DRb server. Im worried about taking a performance hit. I’ll post what I learn when I try it out
Green River
Multiple Effect.toggle
I couldn’t find a clear example on how to handle a blind down and a update with the same onlick event.
Here is what i came up with… im pretty sure there is a better way to do this but this worked just fine.
<span id=”group1_minus” style=”display:none;”><img src=”/images/buttons/small_minus.gif”></span>
<span id=”group1_plus” ><img src=”/images/buttons/small_plus.gif”></span>
<a href=”#” onclick=”Effect.toggle(’blinddown_group1′, ‘blind’, {duration: 0.5}); new Ajax.Updater(’tester’, ‘group1_swap’, {asynchronous:true, evalScripts:true});”>Group 1</a>
<div id=”blinddown_group1″ style=”display:none;”>
#cool stuff here
</div>
Then in the controller:
def group1_swap
render :update do |page|
page[:group1_minus].toggle
page[:group1_plus].toggle
end
end
This worked well for a side nav that needed to blind toggle and swap a +/- graphic to indicate if that section of the nav was open or closed. I havent tried it, but I imagine that you could do many Ajax Updaters in one onclick event.
Pagination with Ferret
I needed simple pagination for ferret search results that were for next page, previous page and go to page.
After working with a couple different pagination plugins i was able to get pagination kind of working. But my design requirements were a little more unique and i needed full controll of the output and view. Then on the ride home it hit me. It’s really simple. I need to take care of just a handfull of options. per_page, page and offset.
It begins by setting these options upstream in the controller:
(params[:p] is coming from the URL to tell me what page im on. If there is no params[:p] just set it to 1.)
if !params[:p]
params[:p] = 1
end
per_page = 50
page = params[:p].to_i #to_i converts a string to a integer
offset = (per_page * page) – per_page
The ferret method is standard:
@results = MyModel.find_by_contents(search_string, :limit => per_page,
ffset => offset)
Now i can control pagination controls like this:
@page_count = @results.total_hits
@current_page = page
@total_pages = @results.total_hits / per_page
@next_page = page + 1
@previous_page = page – 1
Thats it. Now on to the view.
To show Page 2 of 83 do this:
Page <%= @current_page %> of <%= @total_pages %>
To get next page do this:
<a href=”?p=<%= @next_page %>”>Next</a>
To get previous page do this:
<a href=”?p=<%= @previous_page %>”>Previous</a>
To give users the option to jump to a page do this:
Go to page <%= text_field_tag :p %>
Some things to look out for:
@results.total_hits can be a bit unreliable, making pagination unreliable. So far, it seems if the index is clean and not too “fancy” total_hits is pretty accurate. Im still not 100% clear on how to get indexing more reliable for total_hits.
Building site search with Ferret
I recently had the opportunity to build a search feature using the Ferret project.
So I wanted to document what I learned while it was still fresh in mind. First, getting Ferret and acts_as_ferret installed was pretty simple and straight forward. This blog post got me off to a good start.
The first index it created was ok but I was looking for more relevant results. The boost option made the difference I was looking for. Here is how I set it up in my model.
#use acts_as_ferret plug in to assist in creating the index
acts_as_ferret :fields => { :main_tags => { :boost => 4, :store => :yes },
:description => { :boost => 2 },
:keywords => { :boost => 1, :store => :yes }, #have to add store => yes for lazy to work
:photo_code => { :boost => 1 },
}
The production server has over 230k records in it. It took over 6 hours to index everything… (im still working out how to speed that up)… so for development I started with just a few hundred records. That only took a couple of minutes to index.
Once I had my index done I was ready to search it.
search_string = params[:search_term]
@results = Photo.find_by_contents(search_string, :limit => 50) #defaults to 10 results
(pagination notes are coming in a later post)
One of the unique requirements of this project was the need to refine the search on a specific set of keywords. For example, we need to know how many of the search results are also tagged with age, gender or ethnic keywords. So, to know how many of the search results are also tagged with “Mid Adult Women (2,544) ” I used the lazy method in ferret to spare a hit to the database for it. Going to the database for these refine search options put page loads over 10 seconds, 20+ seconds in some cases. Since that is completely unacceptable, Im glad the Ferret team came up with :lazy. It may have saved my job
Photo.find_by_contents(search_string + ” AND Mid Adult Women”, {:lazy => [:keywords]}).total_hits
I learned that find_by_contents will ignore the :condition option for extra query info. But, you can do multiple AND OR statements as part of the search string. Now I can refine my search many times over without ever touching the database!
In the end I am searching over 230k records getting as much as 20k results on some searches and showing total_hits on over 60 refine search options in less than .4 seconds with only one hit to the database. Pretty cool.
Next is pagination
Yellowstone
Yellowstone is one of my most favorite places!
Just got back from a 5 day vacation in YNP and surrounding areas. The kids did really good considering there was a lot of driving and sight seeing. One of the things that made it fun for the kids was that the park has a junior ranger program. They had to pass off a list of requirements that gave them a chance to learn some cool things about the park by themselves.
I had a couple brief oportunities to fish the Firehole. I managed a few small browns and rainbows on a soft-hackle. Also, I had the pleasure of interviewing Bob Jacklyn for my fly fishing podcast.
We took a break from the park and drove to Ennis MT. Just outside of Ennis there is a small ghost town called Nevada City. If you go on a Saturday they have a full cast of characters that you can talk to. They talk and act just as if it was the 1860’s and you are some strange visitor from the future. All the characters were great with the kids and really made the history of they 1860’s come to life.
I can’t wait to go back this October.
Select country onchange update state
I found a lot of different post about this that i couldn’t get to work for me so, here is what i did to get it to work. I was reading on http://api.rubyonrails.org and found remote_function. It was easy from there.
My Controller:
def register
@user = User.new(params[:user])
if request.post? and @user.save
flash.now[:notice] = “User #{@user.username} created”
@user = User.new
end
### a bunch of other code here
@state = ”
end
def dynamic_states
@state = States.find(:all, :conditions => ["country_code = ?", params[:country_id]]).map {|u| [u.name, u.id]}
render :layout => ‘modal’ #just has yield tag in it
end
My Views:
dynamic_states.rhtml:
<%= select(:state, :id, @state) %>
register.rhtml
<select id=”country_id” name=”country_id” onchange=”<%= remote_function(:update => “state_id”,
:with => “‘country_id=’ + $(’country_id’).value”,
:url => { :action => ‘dynamic_states’ }) %>”>
<option>Choose a country</option>
<option value=”US”>United States</option>
<option value=”CA”>Canada</option>
</select>
<div id=”billing_state_id”>
<select>
<option>Choose a country first</option>
</select>
</div>