简体   繁体   中英

Rails active record query to string

When I have the AR query like this :

MyModel.joins(:related_model).where('related_model.some_column = ?', 'somevalue')

If I used to_sql on the above code it would generate something like :

"SELECT * FROM MY_MODEL INNER JOIN RELATED_MODEL ON RELATED_MODEL.SOME_ID = MY_MODEL.SOME_ID WHERE RELATED_MODEL.SOME_COLUMN = 'SOMEVALUE'"

I'm creating a slightly, or way more complex query, and I hate to duplicate code. Is there are way that I can get this part with some command to alter the generated SQL below?

INNER JOIN RELATED_MODEL ON RELATED_MODEL.SOME_ID = MY_MODEL.SOME_ID WHERE RELATED_MODEL.SOME_COLUMN = 'SOMEVALUE'"
foo = MyModel.joins(:related_model).where('related_model.some_column = ?', 'somevalue').to_sql`

core_sql = foo.sub(/^SELECT * FROM MY_MODEL /,'')`

I think will end up needing to be a method of some sort with arrays (or a struct or hash if you want to get more complex).

Using the table_name method to access the underlying table behind a model you could do something like this.

def auto_joins (primary_model, related_models, values)
   search = primary_model + '.table_name'
   primary_table_name = eval(search)
   primary_id = primary_table_name + '_id'
   output_sql = "SELECT * FROM #{primary_table_name}"
   related_models.each do |model|
       search = model + '.table_name'
       table_name = eval(search)
       output_sql += " INNER JOIN #{table_name} ON #{table_name}.#{primary_id} = #{primary_table_name}.id "
   end
   output_sql += "WHERE 1 = 1 " #overcome no values passed in...
   values.each do |where|
        output_sql += "AND #{where}"
   end
   output_sql
end

And in my test database I had contact that had_many leads and prospects I called it like this:

auto_joins('Contact', ['Lead', 'Prospect'], ["contact.first_name = 'Brian'"])

and it generated this:

SELECT * FROM contacts 
  INNER JOIN leads ON leads.contacts_id = contacts.id  
  INNER JOIN prospects ON prospects.contacts_id = contacts.id 
  WHERE 1 = 1 AND contact.first_name = 'Brian'

If you wanted to take it further you could have a hash for {model: 'Contact', where: "first_name = 'Brian'"} and both the where and joins together based on that.

Edit Note: Evals are unsafe if you are exposing any of this to user input. You could find another way to access these models through activerecord and accomplish the same goal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM