+ All Categories
Home > Documents > Son of the Inventory App

Son of the Inventory App

Date post: 09-Jan-2016
Category:
Upload: doane
View: 43 times
Download: 3 times
Share this document with a friend
Description:
Son of the Inventory App. But first. The question came up about how to run a production server with Rails…. Three Possibilities. Use fastcgi and apache Use apache as a proxy server, against a cluster of mongrel servers (this is covered in Agile Web Development with Rails) - PowerPoint PPT Presentation
Popular Tags:
60
Son of the Inventory App
Transcript
Page 1: Son of the Inventory App

Son of the Inventory AppSon of the Inventory App

Page 2: Son of the Inventory App

But firstBut first

The question came up about how to run a production server with Rails…

The question came up about how to run a production server with Rails…

Page 3: Son of the Inventory App

Three PossibilitiesThree Possibilities

Use fastcgi and apache Use apache as a proxy server, against a

cluster of mongrel servers (this is covered in Agile Web Development with Rails)

And the one you want, passenger:http://www.modrails.com/

I'm still playing with this, more to come…

Use fastcgi and apache Use apache as a proxy server, against a

cluster of mongrel servers (this is covered in Agile Web Development with Rails)

And the one you want, passenger:http://www.modrails.com/

I'm still playing with this, more to come…

Page 4: Son of the Inventory App

InstallationInstallation

It's a gem so use "sudo gem install passenger"

Then run:sudo passenger-install-apache2-module

This will install the modules needed

It's a gem so use "sudo gem install passenger"

Then run:sudo passenger-install-apache2-module

This will install the modules needed

Page 5: Son of the Inventory App

Migrate to productionMigrate to production

rake migrate RAILS_ENV=production This will create a new empty database for

a production server You can copy your development db over

the production one if you want to carry your test data over, or dump and load the data

rake migrate RAILS_ENV=production This will create a new empty database for

a production server You can copy your development db over

the production one if you want to carry your test data over, or dump and load the data

Page 6: Son of the Inventory App

ConfigurationConfiguration

In the apache config file, check to make sure you have the modules loading

I had to add these manually on my laptop

In the apache config file, check to make sure you have the modules loading

I had to add these manually on my laptop

LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/ gems/passenger-2.0.3/ext/apache2/mod_passenger.sogems/passenger-2.0.3/ext/apache2/mod_passenger.so

# Passenger config# Passenger configPassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.3PassengerRoot /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.3PassengerRuby /usr/local/bin/rubyPassengerRuby /usr/local/bin/ruby

Page 7: Son of the Inventory App

Virtual HostVirtual Host

You need to define a virtual host This is what I’m using for now Note that I’m using podzone.net, this is dyndns The base uri should point to a soft link to your application's public folder--

doesn't work for me

You need to define a virtual host This is what I’m using for now Note that I’m using podzone.net, this is dyndns The base uri should point to a soft link to your application's public folder--

doesn't work for me

<VirtualHost *:80><VirtualHost *:80> ServerAdmin [email protected] [email protected] DocumentRoot /Library/WebServer/DocumentsDocumentRoot /Library/WebServer/Documents RailsBaseURI /inventoryRailsBaseURI /inventory RailsSpawnMethod conservativeRailsSpawnMethod conservative ServerName avatar.podzone.netServerName avatar.podzone.net</VirtualHost></VirtualHost>

Page 8: Son of the Inventory App

Odds and EndsOdds and Ends

After configuring the web server, restart it:sudo apachectl graceful

Watch your logs:tail -f /var/log/httpd/error_log

After configuring the web server, restart it:sudo apachectl graceful

Watch your logs:tail -f /var/log/httpd/error_log

Page 9: Son of the Inventory App

Tonight and Next WeekTonight and Next Week

Tonight time and date tags lots searches

Next Week more searches email filesystem access ?

Tonight time and date tags lots searches

Next Week more searches email filesystem access ?

Page 10: Son of the Inventory App

When we left our applicationWhen we left our application

A database backend Some Migrations Played with Types Played with Time Methods Some Validations

A database backend Some Migrations Played with Types Played with Time Methods Some Validations

Page 11: Son of the Inventory App

Let's take a look at the sourceLet's take a look at the source

Model Controller Views

Model Controller Views

Page 12: Son of the Inventory App

Next StepsNext Steps

Refine status options Refine date_submitted Add searches

Refine status options Refine date_submitted Add searches

Page 13: Son of the Inventory App

StatusStatus

We can't depend on the user to type what we want

So we need to define what statuses we'll accept ordered, delivered, deployed

Provide a controlled method for selection Radio buttons

We can't depend on the user to type what we want

So we need to define what statuses we'll accept ordered, delivered, deployed

Provide a controlled method for selection Radio buttons

Page 14: Son of the Inventory App

new.html.erbnew.html.erb

In the views/machine dir, we need to edit new.html.erb file

This one's easy, note we're setting a default

In the views/machine dir, we need to edit new.html.erb file

This one's easy, note we're setting a default

<p><p> <%= f.label :status %><br /><%= f.label :status %><br /> <%= f.radio_button :status, "ordered", :checked => true %><%= f.radio_button :status, "ordered", :checked => true %> Ordered <br/>Ordered <br/> <%= f.radio_button :status, "delivered" %>Delivered <br/><%= f.radio_button :status, "delivered" %>Delivered <br/> <%= f.radio_button :status, "deployed" %>Deployed <br/><%= f.radio_button :status, "deployed" %>Deployed <br/> </p></p>

Page 15: Son of the Inventory App

edit.html.erbedit.html.erb

For the edit view, the same thing without the default

For the edit view, the same thing without the default

<p><p> <%= f.label :status %><br /><%= f.label :status %><br /> <%= f.radio_button :status, "ordered" %>Ordered <br/><%= f.radio_button :status, "ordered" %>Ordered <br/> <%= f.radio_button :status, "delivered" %>Delivered <br/><%= f.radio_button :status, "delivered" %>Delivered <br/> <%= f.radio_button :status, "deployed" %>Deployed <br/><%= f.radio_button :status, "deployed" %>Deployed <br/> </p></p>

Page 16: Son of the Inventory App

A validationA validation

We might not need it, but jic Note the use of %w

We might not need it, but jic Note the use of %w

Check status for a valid choiceCheck status for a valid choice validates_inclusion_of \validates_inclusion_of \ :status, \:status, \ :in => %w(ordered delivered deployed), \:in => %w(ordered delivered deployed), \ :message => "Status must be ordered, delivered, or deployed":message => "Status must be ordered, delivered, or deployed"

Page 17: Son of the Inventory App

date_submitteddate_submitted

The date_submitted is just too precise--we don't need the time values, just the date

We're using datetime_select, but time and date methods?

The date_submitted is just too precise--we don't need the time values, just the date

We're using datetime_select, but time and date methods?

date_selectdate_select datetime_selectdatetime_select distance_of_time_in_wordsdistance_of_time_in_words distance_of_time_in_words_to_nowdistance_of_time_in_words_to_now select_dateselect_date select_datetimeselect_datetime select_dayselect_day select_hourselect_hour select_minuteselect_minute select_monthselect_month select_secondselect_second select_timeselect_time select_yearselect_year time_ago_in_wordstime_ago_in_words time_selecttime_select

Page 18: Son of the Inventory App

What's the difference?What's the difference?

date_select, datetime_select, select_time generate inputs tied to an object in the model

select_date, select_datetime, select_day, select_hour, select_minute, select_month, select_second, select_time, select_year produce inputs, but these are not tied to an object in the model

distance_of_time_in_words, distance_of_time_in_words_from_now, time_ago_in_words calculate intervals

This distinction between methods tied to the model and those which are not is pervasive

date_select, datetime_select, select_time generate inputs tied to an object in the model

select_date, select_datetime, select_day, select_hour, select_minute, select_month, select_second, select_time, select_year produce inputs, but these are not tied to an object in the model

distance_of_time_in_words, distance_of_time_in_words_from_now, time_ago_in_words calculate intervals

This distinction between methods tied to the model and those which are not is pervasive

Page 19: Son of the Inventory App

date_selectdate_select

date_select give us an input for just the date

Lots of options

date_select give us an input for just the date

Lots of options

<p><p> <%= f.label :date_submitted %><br /><%= f.label :date_submitted %><br /> <%= f.date_select \<%= f.date_select \ :date_submitted, \:date_submitted, \ :order => [:month, :day, :year], \:order => [:month, :day, :year], \ :start_year => 2008 %>:start_year => 2008 %> </p></p>

Page 20: Son of the Inventory App

Another ValidationAnother Validation

We should also refine the date_submitted validation

We don't allow selection in the past, but we should allow that for at least a week or so in the past

We should limit the future as well

We should also refine the date_submitted validation

We don't allow selection in the past, but we should allow that for at least a week or so in the past

We should limit the future as well

Page 21: Son of the Inventory App

First Try: 1 day ago and ErrFirst Try: 1 day ago and Err This validates that the date and time are reasonable values def date_submitted_must_be_sensible errors.add(:date_submitted, \ 'Time and date cannot be in the past')\ if date_submitted < 3600.mins.ago This one is too restrictive if date_submitted < Time.now errors.add(:date_submitted, \ 'Time and date cannot be more than 2 years in the future')\ if date_submitted > Time.now.advance(:years => 2) is equivalent to: #if date_submitted > 2.years.from_now end

Page 22: Son of the Inventory App

This WorksThis Works # This validates that the date and time are resonable values# This validates that the date and time are resonable values def date_submitted_must_be_sensible def date_submitted_must_be_sensible errors.add(:date_submitted, \errors.add(:date_submitted, \ 'Time and date cannot be more than 2 months in the past')\'Time and date cannot be more than 2 months in the past')\ if date_submitted < 2.months.agoif date_submitted < 2.months.ago # This one is too restrictive# This one is too restrictive # if date_submitted < Time.now# if date_submitted < Time.now errors.add(:date_submitted, \errors.add(:date_submitted, \ 'Time and date cannot be more than 2 years in the future')\'Time and date cannot be more than 2 years in the future')\ if date_submitted > Time.now.advance(:years => 2)if date_submitted > Time.now.advance(:years => 2) # is equivalent to:# is equivalent to: #if date_submitted > 2.years.from_now#if date_submitted > 2.years.from_now end end

Page 23: Son of the Inventory App

Refining Date AppearanceRefining Date Appearance

The inputs are good, but the display leaves a bit to be desired…

The inputs are good, but the display leaves a bit to be desired…

QuickTime™ and a decompressor

are needed to see this picture.

Page 24: Son of the Inventory App

Using strftimeUsing strftime

strftime is a method that will format a datetime object in custom format

The way it works is you call the method with a string that represents the format you want

The % sigil represents a time or date symbol

strftime is a method that will format a datetime object in custom format

The way it works is you call the method with a string that represents the format you want

The % sigil represents a time or date symbol

<p><p> <b>Date submitted:</b><b>Date submitted:</b> <%=h @machine.date_submitted.strftime "%m-%d-%Y" %><%=h @machine.date_submitted.strftime "%m-%d-%Y" %></p></p>

Page 25: Son of the Inventory App

strftime formattingstrftime formatting

Lots of options

There are a few more

I think all of these work with rails

Lots of options

There are a few more

I think all of these work with rails

%a - abbreviated weekday name according to the current locale%a - abbreviated weekday name according to the current locale %A - full weekday name according to the current locale%A - full weekday name according to the current locale %b - abbreviated month name according to the current locale%b - abbreviated month name according to the current locale %B - full month name according to the current locale%B - full month name according to the current locale %c - preferred date and time representation for the current locale%c - preferred date and time representation for the current locale %C - century number (the year divided by 100 and truncated to an integer)%C - century number (the year divided by 100 and truncated to an integer) %d - day of the month as a decimal number (range 01 to 31)%d - day of the month as a decimal number (range 01 to 31) %D - same as %m/%d/%y%D - same as %m/%d/%y %e - day of the month as a decimal number%e - day of the month as a decimal number %g - like %G, but without the century.%g - like %G, but without the century. %H - hour as a decimal number using a 24-hour clock (range 00 to 23)%H - hour as a decimal number using a 24-hour clock (range 00 to 23) %I - hour as a decimal number using a 12-hour clock (range 01 to 12)%I - hour as a decimal number using a 12-hour clock (range 01 to 12) %j - day of the year as a decimal number (range 001 to 366)%j - day of the year as a decimal number (range 001 to 366) %m - month as a decimal number (range 01 to 12)%m - month as a decimal number (range 01 to 12) %M - minute as a decimal number%M - minute as a decimal number %n - newline character%n - newline character %p - either `am' or `pm' according to the given time value%p - either `am' or `pm' according to the given time value %r - time in a.m. and p.m. notation%r - time in a.m. and p.m. notation %R - time in 24 hour notation%R - time in 24 hour notation %S - second as a decimal number%S - second as a decimal number %t - tab character%t - tab character %T - current time, equal to %H:%M:%S%T - current time, equal to %H:%M:%S %u - weekday as a decimal number [1,7], with 1 representing Monday%u - weekday as a decimal number [1,7], with 1 representing Monday

from http://us.php.net/strftime

Page 26: Son of the Inventory App

Refining our indexRefining our index

Currently, the index.html.erb file returns all of the records, by virtue of @machines = Machine.find(:all)

We don't really want that, since any records exported to the main db are not longer relevant @machines = Machine.find(\ :all, \ :conditions => { :exported_to_main => false})

Currently, the index.html.erb file returns all of the records, by virtue of @machines = Machine.find(:all)

We don't really want that, since any records exported to the main db are not longer relevant @machines = Machine.find(\ :all, \ :conditions => { :exported_to_main => false})

Page 27: Son of the Inventory App

SearchesSearches

At this point, we have a pretty nice app But we don't have a search tool We'll want a simple search for the main

page Also an advanced search page with more

options

At this point, we have a pretty nice app But we don't have a search tool We'll want a simple search for the main

page Also an advanced search page with more

options

Page 28: Son of the Inventory App

Simple SearchSimple Search

For this we'll use a find method We'll need an if statement in the controller We'll also need an input on the

index.html.erb file To get started, we'll just search for a name

match

For this we'll use a find method We'll need an if statement in the controller We'll also need an input on the

index.html.erb file To get started, we'll just search for a name

match

Page 29: Son of the Inventory App

The inputThe input

So far, the inputs we have are all associated with objects in the model

We don't need a db entry tho Use an input not linked to the model,

text_field_tag Inputs independent of the model end in

_tag by convention

So far, the inputs we have are all associated with objects in the model

We don't need a db entry tho Use an input not linked to the model,

text_field_tag Inputs independent of the model end in

_tag by convention

Page 30: Son of the Inventory App

The InputThe Input

Here's the input Note the use of the params hash Also that the name of the submit_tag is nil This will default to a get

Here's the input Note the use of the params hash Also that the name of the submit_tag is nil This will default to a get

<p><p> <%= text_field_tag :general_search, params[:search] %><%= text_field_tag :general_search, params[:search] %> <%= submit_tag "General Search", :name => nil %><%= submit_tag "General Search", :name => nil %> </p></p>

Page 31: Son of the Inventory App

An if to catch the searchAn if to catch the search

We need to check if we have the get var Then we set @machines to be the result of a find Here, the find just looks for a match between the

data passed via the get into the params hash and the user_name object in the model…

We need to check if we have the get var Then we set @machines to be the result of a find Here, the find just looks for a match between the

data passed via the get into the params hash and the user_name object in the model…

if params[:general_search]if params[:general_search] @machines = Machine.find(\@machines = Machine.find(\ :all, \:all, \ :conditions => [ "user_name = ?", params[:general_search] ]):conditions => [ "user_name = ?", params[:general_search] ]) endend

Page 32: Son of the Inventory App

findfind

Conditions can be used as a string, array or hash

If you use strings, you should sanitize

Conditions can be used as a string, array or hash

If you use strings, you should sanitize

def self.authenticate_unsafely(user_name, password)def self.authenticate_unsafely(user_name, password) find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'")endenddef self.authenticate_safely(user_name, password)def self.authenticate_safely(user_name, password) find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ])endenddef self.authenticate_safely_simply(user_name, password)def self.authenticate_safely_simply(user_name, password) find(:first, :conditions => { :user_name => user_name, :password => password })find(:first, :conditions => { :user_name => user_name, :password => password })endend

http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001696http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001696

Page 33: Son of the Inventory App

find_by_sql()find_by_sql()

You can also use sql with the find_by_sql method This does tie you to the db backend

You can also use sql with the find_by_sql method This does tie you to the db backend

http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001696http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001696

# A simple SQL query spanning multiple tables Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id" > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]

Page 34: Son of the Inventory App

Refining a findRefining a find

Here, we're using an array with Ors to search the basic text fields

Here, we're using an array with Ors to search the basic text fields

if params[:general_search] #@target = params[:general_search] @machines = Machine.find(:all, \ :conditions => [ \ "user_name = ? OR \ from_entity = ? OR \ from_location = ? OR \ to_entity = ? OR \ to_location = ?", \ params[:general_search], params[:general_search], params[:general_search], params[:general_search], params[:general_search] ]) end

Page 35: Son of the Inventory App

Combining codeCombining code

Right now, this works because we're setting @machines first with a find that looks for records not exported to main, and then reset it if general_search is set in params

This is sloppy, we should combine them So move the first find to an else

Right now, this works because we're setting @machines first with a find that looks for records not exported to main, and then reset it if general_search is set in params

This is sloppy, we should combine them So move the first find to an else

Page 36: Son of the Inventory App

if params[:general_search] @machines = Machine.find(:all, \ :conditions => [ "user_name = ? OR from_entity = ? OR from_location = ? OR to_entity = ? OR to_location = ?", params[:general_search], params[:general_search], params[:general_search], params[:general_search], params[:general_search] ]) else @machines = Machine.find( \ :all, \ :conditions => { :exported_to_main => false}) end

Page 37: Son of the Inventory App

One more thingOne more thing

Our search so far will only find exact matches

We can use a LIKE condition

Notice the use of % and #{}

Our search so far will only find exact matches

We can use a LIKE condition

Notice the use of % and #{}

:conditions => [:conditions => [ "user_name LIKE ? OR "user_name LIKE ? OR from_entity LIKE ? OR from_entity LIKE ? OR from_location LIKE ? OR from_location LIKE ? OR to_entity LIKE ? OR to_entity LIKE ? OR to_location LIKE ?", to_location LIKE ?", "%#{params[:general_search]}%","%#{params[:general_search]}%", "%#{params[:general_search]}%","%#{params[:general_search]}%", "%#{params[:general_search]}%","%#{params[:general_search]}%", "%#{params[:general_search]}%","%#{params[:general_search]}%", "%#{params[:general_search]}%" ])"%#{params[:general_search]}%" ])

Page 38: Son of the Inventory App

Advanced SearchAdvanced Search

We could probably do this with just a new view

But for grins, we'll create a new controller named search with an index page:

ruby script/generate controller search index

We could probably do this with just a new view

But for grins, we'll create a new controller named search with an index page:

ruby script/generate controller search index

Page 39: Son of the Inventory App

A simple pageA simple page

Just to be able to test things out, we'll make a new page, ordered.html.erb in the views/search dir (which was created when we generated the controller)

This will just display some simple results, since we're just testing…

Just to be able to test things out, we'll make a new page, ordered.html.erb in the views/search dir (which was created when we generated the controller)

This will just display some simple results, since we're just testing…

Page 40: Son of the Inventory App

ordered.html.erbordered.html.erb<h1>Ordered Machines</h1><h1>Ordered Machines</h1>

<% for machine in @machines -%> <% for machine in @machines -%> <%=h machine.user_name %><br/><%=h machine.user_name %><br/> <%=h machine.date_submitted.strftime "%m-%d-%Y" %><br/> <%=h machine.date_submitted.strftime "%m-%d-%Y" %><br/> Ticket: <%=h machine.ticket_number %><br/>Ticket: <%=h machine.ticket_number %><br/> From: <%=h machine.from_entity %>From: <%=h machine.from_entity %> To: <%=h machine.to_entity %><br/>To: <%=h machine.to_entity %><br/> <%=h machine.comments %><br/><%=h machine.comments %><br/> <hr/><hr/> <% end %> <% end %>

Page 41: Son of the Inventory App

Try to load itTry to load it

If we load the page using:http://127.0.0.1:3000/search/ordered

we get an error, no method This is because our new controller has no

methods defined

If we load the page using:http://127.0.0.1:3000/search/ordered

we get an error, no method This is because our new controller has no

methods defined

Page 42: Son of the Inventory App

a better finda better find

find as a method is handy, but it's limited For rails 1x, Nick Kallen wrote a plugin,

has_finder, which extended searches This functionality was incorporated into

rails 2.x as named_scope A class method, this will create a custom

method with search conditions

find as a method is handy, but it's limited For rails 1x, Nick Kallen wrote a plugin,

has_finder, which extended searches This functionality was incorporated into

rails 2.x as named_scope A class method, this will create a custom

method with search conditions

Page 43: Son of the Inventory App

machine.erbmachine.erb

In the machine controller, we can create a named scope that finds machines that have been ordered

We can then call this from the search controller We'll do more with named_scope next week--it's

more flexible than find but also a bit confusing

In the machine controller, we can create a named scope that finds machines that have been ordered

We can then call this from the search controller We'll do more with named_scope next week--it's

more flexible than find but also a bit confusing

# Using named_scope, define a search that returns # records of machines that have been ordered named_scope :machines_ordered, :conditions => { :status => "ordered" }

Page 44: Son of the Inventory App

search.erbsearch.erb

In the search controller, we then set a variable

So when we load /search/ordered, the search controller accesses the method we defined in the machine controller, and passes the data to ordered.html.erb

In the search controller, we then set a variable

So when we load /search/ordered, the search controller accesses the method we defined in the machine controller, and passes the data to ordered.html.erb

# This structure accesses a named scope # in machines_controller.erb @machines = Machine.machines_ordered

Page 45: Son of the Inventory App

Ok?Ok?

Yes, this is ok, but if we follow this approach through, we'll wind up with many pages

What would be better would be to use the search/index.html.erb file to allow selection, and then pass the data into the machine/index.html.erb file

So we start with the search/index.html.erb file And we'll start with find…

Yes, this is ok, but if we follow this approach through, we'll wind up with many pages

What would be better would be to use the search/index.html.erb file to allow selection, and then pass the data into the machine/index.html.erb file

So we start with the search/index.html.erb file And we'll start with find…

Page 46: Son of the Inventory App

<h2>Advanced Search</h2><h2>Advanced Search</h2><h3>Choose Field</h3><h3>Choose Field</h3><% form_tag machines_path, :method => 'get' do %><% form_tag machines_path, :method => 'get' do %> <p><p> <%= text_field_tag :search_target, params[:search] %> for<%= text_field_tag :search_target, params[:search] %> for <%= text_field_tag :search_string, params[:search] %><%= text_field_tag :search_string, params[:search] %> <%= submit_tag "Search", :name => nil %><%= submit_tag "Search", :name => nil %> </p></p><% end %><% end %>

search/index.html.erbsearch/index.html.erb

Some text_field_tags and Some text_field_tags and

Page 47: Son of the Inventory App

search/index.html.erbsearch/index.html.erb

This gives us a simple form, for which we enter the field to search and the string to search for

This gives us a simple form, for which we enter the field to search and the string to search for

QuickTime™ and a decompressor

are needed to see this picture.

Page 48: Son of the Inventory App

machine controllermachine controller

Add an if to the controller, this time we'll use a find with slightly different syntax

Add an if to the controller, this time we'll use a find with slightly different syntax

@machines = Machine.find(@machines = Machine.find( :all, :all, :conditions => { params[:search_target] => params[:search_string]}:conditions => { params[:search_target] => params[:search_string]} ) if params[:search_target]) if params[:search_target]

Page 49: Son of the Inventory App

A basic working searchA basic working search

So we have a basic form that has some flexibility for searches

Everything up to this point is in inventory02.gz.tar up in the samples dir

So we have a basic form that has some flexibility for searches

Everything up to this point is in inventory02.gz.tar up in the samples dir

Page 50: Son of the Inventory App

A selectionA selection

What we have works, but it's awkward For our advanced search we need a select We'll start with an html select

What we have works, but it's awkward For our advanced search we need a select We'll start with an html select

<select name="search_target"><select name="search_target"> <option value="user_name">User Name</option><option value="user_name">User Name</option> <option value="from_entity">From Entity</option><option value="from_entity">From Entity</option> <option value="from_location">From Location</option><option value="from_location">From Location</option> <option value="to_entity">To Entity</option> <option value="to_entity">To Entity</option> <option value="to_location">To Location</option> <option value="to_location">To Location</option> </select></select>

Page 51: Son of the Inventory App

select_tagselect_tag

But there's a select_tag we can use, and it has lots of options

A simple use, that's hard coded

But there's a select_tag we can use, and it has lots of options

A simple use, that's hard coded

<%= select_tag "search_target", <%= select_tag "search_target", options_for_select([ "user_name", "from_entity", options_for_select([ "user_name", "from_entity", "from_location" ]) %>"from_location" ]) %>

Page 52: Son of the Inventory App

select_tagselect_tag

select_tag can also take arrays and hashes as parameters

We don't want to have to put data in the views So we can define a constant in the machine.rb file and

call that into the select_tag thusly:

select_tag can also take arrays and hashes as parameters

We don't want to have to put data in the views So we can define a constant in the machine.rb file and

call that into the select_tag thusly:

<%= select_tag "search_target", <%= select_tag "search_target", options_for_select(Machine::CATEGORIES, options_for_select(Machine::CATEGORIES, :multiple => true) %>:multiple => true) %>

Page 53: Son of the Inventory App

Our constantOur constant

In a new data section of the machine.rb file Now we have a user friendly pop up and a

central location for the data

In a new data section of the machine.rb file Now we have a user friendly pop up and a

central location for the data

CATEGORIES=CATEGORIES= {{ 'User Name' => 'user_name', 'User Name' => 'user_name', 'From Entity' => 'from_entity', 'From Entity' => 'from_entity', 'From Location' => 'from_location','From Location' => 'from_location', 'To Entity' => 'to_entity','To Entity' => 'to_entity', 'To Location' => 'to_location''To Location' => 'to_location' }}

Page 54: Son of the Inventory App

So far so goodSo far so good

But this again depends on exact matches And this is in a hash structure--according

to the docs, you can use a LIKE in a hash

But this again depends on exact matches And this is in a hash structure--according

to the docs, you can use a LIKE in a hash

@machines = Machine.find(@machines = Machine.find( :all, :all, :conditions => { params[:search_target] => :conditions => { params[:search_target] => params[:search_string]}params[:search_string]} ) if params[:search_target]) if params[:search_target]

Page 55: Son of the Inventory App

Changed to an ArrayChanged to an Array

This change is easy Notice the if, that keeps this one from

interfering with the general search

This change is easy Notice the if, that keeps this one from

interfering with the general search

# Array structure, can use LIKE# Array structure, can use LIKE @machines = Machine.find(@machines = Machine.find( :all, :all, :conditions => [ "#{params[:search_target]} LIKE ?", :conditions => [ "#{params[:search_target]} LIKE ?", params[:search_string] ]params[:search_string] ] ) if params[:search_target]) if params[:search_target]

Page 56: Son of the Inventory App

Controller vs ModelController vs Model

This search is all in the controller Ideally, we'd want the model to do the

heavy lifting One stop shopping Write once, use anywhere

So, we define a method in the model

This search is all in the controller Ideally, we'd want the model to do the

heavy lifting One stop shopping Write once, use anywhere

So, we define a method in the model

def self.search_string(target, string)def self.search_string(target, string) find(:all, :conditions => [ "#{target} LIKE ?", "%#{string}%" ]) find(:all, :conditions => [ "#{target} LIKE ?", "%#{string}%" ]) endend

Page 57: Son of the Inventory App

Call Method from ControllerCall Method from Controller

And we can call this from the controller And we can call this from the controller

@machines = Machine.search_string(params[:search_target], params[:search_string]) if params[:search_target]

Page 58: Son of the Inventory App

Back to our general searchBack to our general search

We've stuck that in the controller, too So move that into the model This one's longer, but the idea is the same

We've stuck that in the controller, too So move that into the model This one's longer, but the idea is the same

Page 59: Son of the Inventory App

def self.general_search(search)def self.general_search(search) if searchif search find(:all,find(:all, :conditions => [:conditions => [ "user_name LIKE ? OR "user_name LIKE ? OR from_entity LIKE ? OR from_entity LIKE ? OR from_location LIKE ? OR from_location LIKE ? OR to_entity LIKE ? OR to_entity LIKE ? OR to_location LIKE ?", to_location LIKE ?", "%#{search}%","%#{search}%", "%#{search}%","%#{search}%", "%#{search}%","%#{search}%", "%#{search}%","%#{search}%", "%#{search}%" ])"%#{search}%" ]) elseelse find(:all, :conditions => { :exported_to_main => false})find(:all, :conditions => { :exported_to_main => false}) endend endend


Recommended