All, I''m new to ruby and to rails! :-) This will give you all a chance to tear my code apart! Feel free to offer better techniques as necessary! I have a need to implement somewhat dynamic search across several different entities. In one of my controllers, I have an action called search. I have some code working to do a search based on parameters from a form submit. Now, I want to make the search routine available to all controllers. I''m trying to figure out if I can dynamically name variables in ruby or not based on input args to a function. Here is the code I have in the controller: @whereClause = "" @params[:price_quote].each { | key, value | if value.length > 0 @whereClause = @whereClause.length == 0 ? "#{key} = #{value}" : @whereClause << " and #{key} = #{value}" end } if @whereClause.length > 0 then @price_quote_pages, @price_quotes = paginate :price_quote, :per_page => 10, :conditions => @whereClause else @price_quote_pages, @price_quotes = paginate :price_quote, :per_page => 10 end I would like to have a function called "getSearchResults" or something similar where I pass in the name of the controller and the param hash. Based on the input args, it would find the proper hash and create the page objects with the controller name. Any suggestions? Michael --------------------------------- Yahoo! FareChase - Search multiple travel sites in one click. _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
On Friday 11 November 2005 7:27 am, Michael wrote:> I would like to have a function called "getSearchResults" or something > similar where I pass in the name of the controller and the param hash. > Based on the input args, it would find the proper hash and create the page > objects with the controller name. > > Any suggestions?Hi Michael, I''m quite new to Rails myself, but I''ll try to help. Start by putting a function in app/controllers/application.rb: private def dynamic_search( options = { :controller_name => "default_controller", :search_params => {} }) controller_name = options[:controller_name] search_params = options[:search_params] # (your search code here) end Then in any of your app''s controllers you can call it using: @results = dynamic_search( :controller_name => "some_controller", :search_params => { :key1 => "value1", :key2 => "value2", etc}) Using this technique, you could omit either of the parameters passed to the function by replacing "default_controller" with the name of, well, your default controller, and adding code to your search routine to handle the parameters. Here''s a hint: for column in Price_quote.content_columns ... end Will let you iterate through the column names of the db table. Good luck. (The more experienced of you please correct me where I''m wrong) -- Mark Beattie Easy Schedule Management http://easy-online-schedule.com
Mark, Thank you for the input. I already have the column names and values to search on - they were in the params hash from my original sample. I get them when the user submits the search form. @params[:price_quote].each { | key, value | .... What I really would like to know how to do, though, is somehow dynamically name the objects. For example, If I tell the function that this is for the price_quote controller, then I want it to create the proper pagination objects for me. Taking the sample from below, I want to be able to name "@price_quote_pages" based on the input of the function. It could be "@lead_pages", "@activity_pages", etc... if @whereClause.length > 0 then @price_quote_pages, @price_quotes = paginate :price_quote, :per_page => 10, :conditions => @whereClause ... The views rely on the name of these pagination objects to navigate forward and backward through the records. All in all, this search actually sucks pretty badly! It isn''t flexible at all. I had a bug in my original post whereby I didn''t surround the param values with single quotes (worked great for numeric fields though)..hahaha. I just need something basic for simple search on multiple fields without having to hard code the names (e.g. ActiveRecord.find_all_by...and....and...) and get the results into a pagination object! Thanks, Michael Mark Beattie <beattie.mark-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: On Friday 11 November 2005 7:27 am, Michael wrote:> I would like to have a function called "getSearchResults" or something > similar where I pass in the name of the controller and the param hash. > Based on the input args, it would find the proper hash and create the page > objects with the controller name. > > Any suggestions?Hi Michael, I''m quite new to Rails myself, but I''ll try to help. Start by putting a function in app/controllers/application.rb: private def dynamic_search( options = { :controller_name => "default_controller", :search_params => {} }) controller_name = options[:controller_name] search_params = options[:search_params] # (your search code here) end Then in any of your app''s controllers you can call it using: @results = dynamic_search( :controller_name => "some_controller", :search_params => { :key1 => "value1", :key2 => "value2", etc}) Using this technique, you could omit either of the parameters passed to the function by replacing "default_controller" with the name of, well, your default controller, and adding code to your search routine to handle the parameters. Here''s a hint: for column in Price_quote.content_columns ... end Will let you iterate through the column names of the db table. Good luck. (The more experienced of you please correct me where I''m wrong) -- Mark Beattie Easy Schedule Management http://easy-online-schedule.com _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails --------------------------------- Yahoo! FareChase - Search multiple travel sites in one click. _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
On Friday 11 November 2005 10:38 am, Michael wrote:> What I really would like to know how to do, though, is somehow dynamically > name the objects. For example, If I tell the function that this is for the > price_quote controller, then I want it to create the proper pagination > objects for me. Taking the sample from below, I want to be able to name > "@price_quote_pages" based on the input of the function. It could be > "@lead_pages", "@activity_pages", etc...I don''t think the controller is determined by the paginator. I''m thinking that you can pass whatever controller you want to the links generated from the paginator in your view: <%= link_to ''Previous page'', {:controller => @whatever, :page => @price_quote_pages.current.previous, :search => @params[''search''], :order_by => @params[''order_by''], :order_dir => @params[''order_dir''] } if @price_quote_pages.current.previous %> and <%= link_to ''Next page'', {:controller => @whatever, :page => @price_quote_pages.current.next, :search => @params[''search''], :order_by => @params[''order_by''], :order_dir => @params[''order_dir''] } if @price_quote_pages.current.next %> Check out the docs for the link_to helper: http://api.rubyonrails.com/classes/ActionView/Helpers/UrlHelper.html#M000325 link_to probably defaults to the current controller unless told otherwise. -- Mark Beattie Easy Schedule Management http://easy-online-schedule.com
Hi Michael, I''m also fairly new to rails, and I have been looking at this same issue. With some help from the people on rubyonrails irc I put together the following in application.rb def search conditions = "0" params.delete("controller") # is there a better way to extract these terms??? params.delete("action") params.delete("page") params.each {|key, value| conditions+= " OR #{key} LIKE ''%#{value}%''" } @name = self.controller_name() @item_pages, @items = paginate @name.to_sym, :per_page => 5, :conditions => conditions @model = Kernel.const_get(@name.camelize) render :layout => ''mylayout'' end and then I drop the following into each view as search.rhtml <% for item in @items %> <div id="item<%= item.id %>" class="orangebox"> <% for column in @model.content_columns %> <%=h item.send(column.name) %><br> <%end%> <%= link_to ''Show'', :action => ''show'', :id => item %> <%= link_to ''Edit'', :action => ''edit'', :id => item %> <%= link_to_remote "Remove", :url=>{ :controller=>"items", :action=>"destroy", :id=>item}, :loading=>"status(''item#{item.id}'')", :complete=>"new Effect.Fade(''item#{item.id}'')" %> </div> <% end %> <%= pagination_links(@item_pages, {:params=>params}) %> <br /> and now every one of my controllers that has an associated model name (e.g. recipes_controller and recipe) has search available, e.g. http://rails/recipes/search?title=trifle I wonder if this meets all your needs. CHEERS> SAM Michael wrote:> All, > > I''m new to ruby and to rails! :-) This will give you all a chance > to tear my code apart! Feel free to offer better techniques as necessary! > > I have a need to implement somewhat dynamic search across several > different entities. > > In one of my controllers, I have an action called search. I have some > code working to do a search based on parameters from a form submit. > Now, I want to make the search routine available to all controllers. > I''m trying to figure out if I can dynamically name variables in ruby > or not based on input args to a function. > > Here is the code I have in the controller: > > @whereClause = "" > @params[:price_quote].each { | key, value | > if value.length > 0 > @whereClause = @whereClause.length == 0 ? "#{key} = #{value}" : > @whereClause << " and #{key} = #{value}" > end > } > > if @whereClause.length > 0 then > @price_quote_pages, @price_quotes = paginate :price_quote, > :per_page => 10, :conditions => @whereClause > else > @price_quote_pages, @price_quotes = paginate :price_quote, > :per_page => 10 > end > I would like to have a function called "getSearchResults" or something > similar where I pass in the name of the controller and the param > hash. Based on the input args, it would find the proper hash and > create the page objects with the controller name. > > Any suggestions? > > Michael > > > ------------------------------------------------------------------------ > Yahoo! FareChase - Search multiple travel sites in one click. > <http://us.lrd.yahoo.com/_ylc=X3oDMTFqODRtdXQ4BF9TAzMyOTc1MDIEX3MDOTY2ODgxNjkEcG9zAzEEc2VjA21haWwtZm9vdGVyBHNsawNmYw--/SIG=110oav78o/**http%3a//farechase.yahoo.com/> > > >------------------------------------------------------------------------ > >_______________________________________________ >Rails mailing list >Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >http://lists.rubyonrails.org/mailman/listinfo/rails > >
On 11/21/05, Sam Joseph <sam-wUweuJJ0J032eFz/2MeuCQ@public.gmane.org> wrote:> I''m also fairly new to rails, and I have been looking at this same > issue. With some help from the people on rubyonrails irc I put together > the following in application.rbI really hope nobody on IRC actually told you to use the code below. While the method they gave you will work it has an obvious SQL injection vulnerability.> > def search > conditions = "0" > params.delete("controller") # is there a better way to extract > these terms??? > params.delete("action") > params.delete("page") > params.each {|key, value| conditions+= " OR #{key} LIKE ''%#{value}%''" } > @name = self.controller_name() > @item_pages, @items = paginate @name.to_sym, :per_page => 5, > :conditions => conditions > @model = Kernel.const_get(@name.camelize) > render :layout => ''mylayout'' > endYou should not be trusting the data given in params. You should be checking key against a list of known good keys, and using ? as placeholders for values. Maybe something like: def search valid_keys = %w''foo bar baz'' conditions = [''0''] valid_keys.each do |key| if params.include?(key) conditions[0] << " OR #{key} LIKE ?" conditions << "%#{params[key]}%" end end @name = self.controller_name() @item_pages, @items = paginate @name.to_sym, :per_page => 5, :conditions => conditions @model = Kernel.const_get(@name.camelize) render :layout => ''mylayout'' end That''s untested, but it shouldn''t be vulnerable. You should never, ever, under any circumstances, trust data that is in params. You should be checking, filtering, and/or scrubbing all client data before using it in your SQL queries (protection against SQL injection) or displaying it on your page (protection against cross site scripting). Rails makes SQL injection protection easy, by submitting an array for conditions using ? as placeholders for variables. I haven''t read the AWDR book, but I''m guessing (hoping) there is a section on this.