开发者

How to make optional :conditions for a find

开发者 https://www.devze.com 2023-01-05 10:26 出处:网络
Hello I have the followong struggle in my head. I want a text-field in which the use can type in some parameters, which will be used as filter-criteria for the :conditions hash in my find method.

Hello I have the followong struggle in my head. I want a text-field in which the use can type in some parameters, which will be used as filter-criteria for the :conditions hash in my find method.

I have created a helper, with takes an option and merge the hash to the options:

In my controller:

@bills =开发者_高级运维 adminbill_filter(:limit=>params[:limit] || 50,:offset=>params[:offset] || 0, :conditions=>params[:options])

In my helper:

  def link_to_with_current(text, link, condition, *args)
    options = args.first || {}
    options[:class] = condition ? 'current' : nil
    link_to text, link, options
  end

In my view:

<%= text_field :filter ,:criteria, :class=>'roundRect',:id=>'name', :value=>12009%>
<%= button_to_with_filter 'Start Filter', 'index', :filter_condition=>true, :options=>{:id=>81}%>

Is it somehow possible to pass the value of text_field into the :option=>{...} of the button_to_with_filter? I find this solution (if it is working) quite unhandy. Your comments are as always very helpful.

Greetings Matthias


It seems kind of terrifying to put in the contents of user-submitted params without vetting them in any capacity. You're probably going to run into all kinds of exceptions if the data doesn't come in as expected, or is formulated to be malicious.

I've found it's often easier to use a chained scopes approach:

def index
  bills_scope = Bill

  # Use an example Bill.with_id scope
  if (params[:with_id])
    bills_scope = bills_scope.with_id(params[:with_id])
  end

  # Repeat as required

  # Finally, use the scope to retrieve matching records
  @bills = bills_scope.paginated
end

Using something like will_paginate can help with your offset and limit values.


If the text field and button were encapsulated in a form, and the button was the submit button, the text field's value would automatically be brought into the params hash. Then you wouldn't have to deal with it. I can't recall at the moment the exact Rails helpers that will do this for you, but you want the resulting form to probably be something like this:

<% form_for :options, :url => {:action => :index}, :html => { :method => :get } do |f| %>
<%= f.text_field :filter ,:criteria, :class=>'roundRect',:id=>'name', :value=>12009%>
<%= f.submit 'Start Filter' %>
<% end %>

Which may change some, since I don't know the underlying code behind your methods.

Otherwise, the only thing I can think of is using a Javascript event on the button that grabs the value of the text field before it submits.


Thanks for your help, I came across named_scope and solved the problem with the following code:

Bill model:

class Bill < ActiveRecord::Base
  # named_scope werden fuer Filterfunktionen bei Adminbill benoetigt
  named_scope :standard, :order => "created_at DESC"
  named_scope :limit, lambda {|*args| {:limit=>(args.first)|| 50}}
  named_scope :offset, lambda {|*args| {:offset=>(args.first || 10)}}
  named_scope :paid, :conditions=>"paid IS NOT NULL"
  named_scope :not_paid, :conditions=>{:paid=>nil}
  named_scope :test_bill, :conditions => {:test_bill=>true}
  named_scope :no_test_bill, :conditions => {:test_bill=>false}
  named_scope :find_via_bill_id, lambda {|*args|{:conditions=>{:id=>(args.first || 210)}}}
  named_scope :find_via_email, lambda {|*args| {:conditions=>{:buyer_id=>args.first}}}

controller:

  def index
logger.debug "The object is #{current_user}"

if params[:filterInput] != nil && !params[:filterInput].empty?
  filter_array = params[:filterInput].split('&')
  bill_scope = Bill.scoped({})
  bill_scope = bill_scope.standard

  # Filtere via Regexp-Matching die Zahlen der Eingabe heraus 
  filter_array.each do |el|
    if el =~ /limit\([0-9]+\)/
      number = 
      bill_scope = bill_scope.limit(el.scan(/\d+/)[0])
    elsif el =~ /offset\([0-9]+\)/
      bill_scope = bill_scope.offset(el.scan(/\d+/)[0])
    elsif el == 'paid'
      bill_scope = bill_scope.paid
    elsif el == 'not_paid'
      bill_scope = bill_scope.not_paid
    elsif el == 'test_bill'
      bill_scope = bill_scope.test_bill
    elsif el =~ /find_via_bill_id\([0-9]+\)/
      bill_scope = bill_scope.find_via_bill_id(el.scan(/\d+/)[0])
    elsif el =~ /find_via_email\([A-Za-z0-9.@-]+\)/
      email = el.scan(/\([A-Za-z0-9.@-]+\)/)[0]
      # TODO geht bestimmt auch eleganter durch besseres Matching
      email = email.gsub("(", "")
      email = email.gsub(")", "")
      user =  User.find_by_email(email) unless User.find_by_email(email).blank?
      bill_scope = bill_scope.find_via_email(user.id)
    end
  end
  @bills = bill_scope
else 
  @bills = Bill.standard.limit.offset
end

And in the view:

<% form_tag(:action => 'index') do %>
   <%= text_field_tag 'filterInput', nil, :size => 40 %> 
  <%= submit_tag 'Start Filter'%>
<% end %>

Now you can pass in the tex-field e.g.the following valid expression: paid&limits(20) I know that the controller solution isn't very elegant but for me it was the fastest way to solve this problem.

0

精彩评论

暂无评论...
验证码 换一张
取 消