tutorial rails que heinemeier hansson ejemplos descargar david curso ruby-on-rails ruby ruby-on-rails-3 activerecord gem

ruby on rails - que - Constructor de consultas SQL Rails... o generador de consultas ActiveRecord



ruby on rails tutorial (3)

Necesito ejecutar la consulta SQL como

sql = ''SELECT * FROM users WHERE id != '' + self.id.to_s + '' AND id NOT IN (SELECT artner_id FROM encounters WHERE user_id = '' + self.id.to_s + '')'' sql += '' AND id NOT IN (SELECT user_id FROM encounters WHERE partner_id = '' + self.id.to_s + '' AND predisposition = '' + Encounter::Negative.to_s + '')'' sql += '' AND cfg_sex = '' + self.sex.to_s + '' AND cfg_country = '' + self.country.to_s + '' AND cfg_city = '' + self.city.to_s sql += '' ORDER BY rand() LIMIT 1''

Se puede ejecutar mediante AR.find_by_sql, pero el código anterior es de mala lectura. ¿Hay algún generador de consultas que pueda generar esa consulta?

Por ejemplo, Kohana (es framework PHP, soy desarrollador php, pero quiero cambiar ese lenguaje secundario a ruby ​​/ rails) tengo un generador de consultas, que funciona así:

$sql = DB::select(''*'')->from(''users''); $sql->where(''id'', ''NOT_IN'', DB::expr(''SELECT partner_id FROM encounters WHERE user_id = ''.$user->id)); $sql->where(''id'', ''NOT_IN'', DB::expr(''SELECT user_id FROM encounters WHERE partner_id = ''.$user->id.'' AND predisposition = ''.Encounter::Negative)); .... etc ...

La consulta que se construyó con el generador de consultas como un generador de consultas de Kohana es más legible y comprensible.

¿Hay alguna joya para resolver este problema?


Hay una biblioteca de rubíes que utiliza álgebra relacional. Se llama ARel . Si está utilizando Rails 3.x, entonces ya lo tiene.

ids = Partner.where(user_id: self.id).pluck(:partner_id) << self.id users = User.where("id NOT IN #{ ids.join('','') }")


Aquí está el mismo molde de consulta en los términos de AREL de rieles. Todavía no es bonito, es una consulta complicada en general.

User.where("id = ? AND " "id NOT IN (SELECT artner_id FROM encounters WHERE user_id = ?) AND " + "id NOT IN (SELECT user_id FROM encounters WHERE partner_id = ? AND predisposition = ? ) AND " + "cfg_sex = ? AND cfg_country = ? AND cfg_city = ?)", self.id, self.id, self.id, Encounter::Negative, self.sex, self.country, self.city).order(" rand() ").limit(1)

(No he probado esto, por lo que es posible que haya errores tipográficos).

Yo recomendaría un par de cosas:

Cuando tienes cláusulas complejas donde se pueden encadenar entre sí, AREL las volverá a unir bastante bien. Esto le permite usar ámbitos en sus clases modelo y encadenarlos.

Por ejemplo, podrías hacer esto:

User < ActiveRecord::Base self.def in_city_state_country(city, state, country) where("cfg_sex = ? AND cfg_country = ? AND cfg_city = ?", city, state, country) end self.def is_of_sex(sex) where("cfg_sex = ?", sex) end end

Entonces podría reescribir estas partes de la consulta de esta manera:

User.is_of_sex(user.sex).in_city_state_country(user.city, user.state, user.country)

y así.

Al dividir las consultas en partes más pequeñas también es más fácil probar piezas específicas con tus rspecs. Resulta en un código más modular y mantenible.

Para obtener más detalles, consulte la Guía de Rails - Interfaz de consulta de registros activos


Necesitas la gema squeel . Amplía AR con bloques y realiza consultas muy complicadas con facilidad.

Solo algunas características:

# not_in == cool! ) Product.where{id.not_in LineItem.select{product_id}} # SELECT "products".* FROM "products" WHERE "products"."id" NOT IN # (SELECT "line_items"."product_id" FROM "line_items" ) # outer joins on pure Ruby: LineItem.joins{product.outer} # LineItem Load (0.0ms) SELECT "line_items".* FROM "line_items" # LEFT OUTER JOIN "products" ON "products"."id" = "line_items"."product_id" # calcs, aliasing: Product.select{[avg(price).as(middle)]} # SELECT avg("products"."price") AS middle FROM "products" # comparison Product.where{id != 100500} Product.where{price<10} # logical OR Product.where{(price<10) | (title.like ''%rails%'')} # SELECT "products".* FROM "products" WHERE (("products"."price" < 10 OR # "products"."title" LIKE ''%rails%'')) # xxx_any feature (also available xxx_all) Product.where{title.like_any %w[%ruby% %rails%]} # SELECT "products".* FROM "products" WHERE (("products"."title" LIKE ''%ruby%'' OR # "products"."title" LIKE ''%rails%''))

Tenga en cuenta que el uso de bloques: {...} aquí no son hashes. También tenga en cuenta la ausencia de símbolos.

Si decide elegirlo, lea la sección que comienza con "Esto conlleva una implicación importante"