Skip to main content
deleted 14 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

how to filter Filtering (search) a model with multiple params in hash

thisThis function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

  def search opts # This default doesn't work the way I would like = {:user_type => :family}
    
    #TODO: default opts value in method sign if possible
    opts[:user_type] ||= :family

    # initial criteria
    fields= "user_type= ?"
    values= [opts[:user_type]]
   
    # each field filters the list in one of these three ways
    staight_fields = [ :country, :first_name, :last_name, :nationality ]
    like_fields = [:country_preferences, :keyword, :languages ]
    bool_fields = [:driver, :housework, :children ]

    # cicle the options and build the query    
    opts.each do |k, v|
      if straight_fields.include? k
        fields += " AND #{k} = ?"
        values += v
      elsif like_fields.include? k
        fields += " AND #{k} like %?%"
        values += v
      elsif bool_fields.include? k
        fields += " AND #{k} = ?"
        values += v == 'true'
      else
        logger.warn "opts #{k} with value #{v} ignored from search"
      end
    end
   
    # execute the query and return the result
    self.registered.actives.where([fields] + values)   
  end
  

I think I can use more scope but how can I combine them together? In general, how can I make this code much better?

PS: The boss, when introducing the project, said one-to-many relationships for that kind of fields would be a pain in the back, what. What do you think about this pragmatic solution?

how to filter (search) a model with multiple params in hash

this function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

  def search opts # This default doesn't work the way I would like = {:user_type => :family}
    
    #TODO: default opts value in method sign if possible
    opts[:user_type] ||= :family

    # initial criteria
    fields= "user_type= ?"
    values= [opts[:user_type]]
   
    # each field filters the list in one of these three ways
    staight_fields = [ :country, :first_name, :last_name, :nationality ]
    like_fields = [:country_preferences, :keyword, :languages ]
    bool_fields = [:driver, :housework, :children ]

    # cicle the options and build the query    
    opts.each do |k, v|
      if straight_fields.include? k
        fields += " AND #{k} = ?"
        values += v
      elsif like_fields.include? k
        fields += " AND #{k} like %?%"
        values += v
      elsif bool_fields.include? k
        fields += " AND #{k} = ?"
        values += v == 'true'
      else
        logger.warn "opts #{k} with value #{v} ignored from search"
      end
    end
   
    # execute the query and return the result
    self.registered.actives.where([fields] + values)   
  end
  

I think I can use more scope but how can I combine them together? In general, how can I make this code much better?

PS: The boss when introducing the project said one-to-many relationships for that kind of fields would be a pain in the back, what do you think about this pragmatic solution?

Filtering (search) a model with multiple params in hash

This function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

  def search opts # This default doesn't work the way I would like = {:user_type => :family}
    
    #TODO: default opts value in method sign if possible
    opts[:user_type] ||= :family

    # initial criteria
    fields= "user_type= ?"
    values= [opts[:user_type]]
   
    # each field filters the list in one of these three ways
    staight_fields = [ :country, :first_name, :last_name, :nationality ]
    like_fields = [:country_preferences, :keyword, :languages ]
    bool_fields = [:driver, :housework, :children ]

    # cicle the options and build the query    
    opts.each do |k, v|
      if straight_fields.include? k
        fields += " AND #{k} = ?"
        values += v
      elsif like_fields.include? k
        fields += " AND #{k} like %?%"
        values += v
      elsif bool_fields.include? k
        fields += " AND #{k} = ?"
        values += v == 'true'
      else
        logger.warn "opts #{k} with value #{v} ignored from search"
      end
    end
   
    # execute the query and return the result
    self.registered.actives.where([fields] + values)   
  end

I think I can use more scope but how can I combine them together? In general, how can I make this code much better?

The boss, when introducing the project, said one-to-many relationships for that kind of fields would be a pain in the back. What do you think about this pragmatic solution?

Rollback to Revision 2
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Thisthis function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation).

  I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

PS: The boss when introducing the project said one-to-many relationships for that kind of fields would be a pain in the back, what do you think about this pragmatic solution?

EDIT: I had a good look and I found that scopes really helps me out!!

so now the code is this one, I just miss to insert some scopes for those multiselect-string, but it's already much better.

EDIT2:@sepp2k correctly pointed out an error that is now corrected (thank you)

  def self.search(params)
    profiles = scoped_by_active(true).scoped_by_registered(true)
    profiles = profiles.scoped_by_user_type(params[:user_type]) unless params[:user_type].blank?
    [...]
    profiles = profiles.scoped_by_driver(params[:driver] == 'true') unless params[:driver].blank?    
    profiles.scoped_including_language(params[:language]) unless params[:language].blank?
  end

NOTE: scoped_by_field_name comes from rails and scoped_including_languages is devloped as suggested by @Beerlington.

I'm still wondering if this way to put multi-data in a string really makes things easier.

This function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation).

  I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

PS: The boss when introducing the project said one-to-many relationships for that kind of fields would be a pain in the back, what do you think about this pragmatic solution?

EDIT: I had a good look and I found that scopes really helps me out!!

so now the code is this one, I just miss to insert some scopes for those multiselect-string, but it's already much better.

EDIT2:@sepp2k correctly pointed out an error that is now corrected (thank you)

  def self.search(params)
    profiles = scoped_by_active(true).scoped_by_registered(true)
    profiles = profiles.scoped_by_user_type(params[:user_type]) unless params[:user_type].blank?
    [...]
    profiles = profiles.scoped_by_driver(params[:driver] == 'true') unless params[:driver].blank?    
    profiles.scoped_including_language(params[:language]) unless params[:language].blank?
  end

NOTE: scoped_by_field_name comes from rails and scoped_including_languages is devloped as suggested by @Beerlington.

I'm still wondering if this way to put multi-data in a string really makes things easier.

this function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

PS: The boss when introducing the project said one-to-many relationships for that kind of fields would be a pain in the back, what do you think about this pragmatic solution?

added 4 characters in body
Source Link

thisThis function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). 

I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

this function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

This function in my Profile model receive a hash from a search form and should filter the table depending on those values. I guess there is something like a pattern for such a standard behavior, right now I ended up with this (unfortunately I had to reproduce the code here, so it might not work for some reasons, but you get the idea).

Just a note: we're storing in the model some strings containing multiple data, each of these fields should be a one-to-many relationship (db normality violation). 

I give an example: country_preferences is a string filled up by an html select :multiple => true. In the string I then find values like: ["Australia", "China", "United Kingdom"].

added 11 characters in body
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
final refactor, code working
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
added 5 characters in body
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
corrected after @sepp2k comment
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
big refactor using scopes, but still some work to do...; added 6 characters in body; added 61 characters in body
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
minor correction in the code
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading
Source Link
ecoologic
  • 795
  • 2
  • 10
  • 19
Loading