简体   繁体   English

Active Record子句不起作用的多重链

[英]Chain of multiple where Active Record clauses not working

I am fairly new to Ruby on Rails and ActiveRecord. 我是Ruby on Rails和ActiveRecord的新手。 I have a database model named location which describes a point of interest on a map. 我有一个名为location的数据库模型,它描述了地图上的兴趣点。 A location has a location_type field that can have three different location types (business, dispensary or contact). 位置具有location_type字段,该字段可以具有三种不同的位置类型(公司,药房或联系人)。 A location also has an owner_id as well which is the user_id of the user who created the location. 位置也具有owner_id ,它是创建位置的用户的user_id

In the controller the user requests all of their locations by providing their ID. 在控制器中,用户通过提供其ID来请求其所有位置。 The dispensary and business locations are public so all users should be able to view them, while the contacts should only be shown to the user who is the owner of them. 药房和营业地点是公开的,因此所有用户都应该能够查看它们,而联系人仅应显示给拥有它们的用户。 Therefore I am tasked with creating an ActiveRecord query that returns all dispensaries and businesses in the database and all contacts that were created by that user. 因此,我的任务是创建一个ActiveRecord查询,该查询返回数据库中的所有药房和企业以及该用户创建的所有联系人。 I was trying to do this by chaining together where clauses but for some reason this has failed: 我试图通过将where子句链接在一起来实现此目的,但是由于某种原因,此操作失败了:

@locations = Location.where(:location_type => ["business", "dispensary"]).where(:location_type => "contact", :owner_id => params[:id])

Which generates this PostgreSQL: 生成此PostgreSQL:

SELECT "locations".* FROM "locations"  WHERE "locations"."location_type" IN ('business', 'dispensary') AND "locations"."location_type" = 'contact' AND "locations"."owner_id" = 1

I suspect that this failed because the first where returns just the locations of type business and dispensary and the second where queries that returned data which has no locations of type contact within it. 我怀疑这失败,因为第一where返回式业务和取药的第二只的位置where一个返回具有内它类型的接触中没有任何位置数据的查询。 How can I query for all dispensaries and businesses combined with a set of filtered contacts? 如何查询所有药房和企业,以及一组经过筛选的联系人?

Chaining where calls like that will result in AND s at the SQL level. where调用处进行链接将在SQL级别导致AND where can take raw SQL for an argument, in which you could explicitly add an OR , but parameterizing it properly is rather messy IMO (although it can be done). where可以将原始SQL用作参数,您可以在其中显式添加OR ,但是正确地对其进行参数化是相当麻烦的IMO(尽管可以做到)。 So, for this type of query, I think it would probably be best to drop down into using raw SQL with sanitized inputs (to guard against SQL injection). 因此,对于这种类型的查询,我认为最好是使用带有经过清理的输入的原始SQL(以防止SQL注入)。

ie something like this: 即这样的事情:

x = ActiveRecord::Base.connection.raw_connection.prepare(
    "SELECT * FROM locations
     WHERE location_type IN ('business', 'dispensary') OR
           (location_type = 'contact' AND owner_id = ?)")
x.execute(params[:id])
x.close

This will select all items from the locations table where the location_type is either 'business' or 'dispensary', regardless of the owner_id , and all items where the location_type is 'contact' where the owner_id` matches the one passed in. 这将从locations表中选择location_type为'business'或'dispensary'的所有项目,而与owner_id is 'contact' where the owner_id与传入is 'contact' where the项目相匹配的location_type is 'contact' where the所有项目。

Edit in response to comment from OP: 根据OP的评论进行编辑:

I tend to prefer raw SQL whenever possible for more complex queries, as I find it easier to control the behavior (ORMs can sometimes do things that are less than desirable, such as executing the same query 1000 times to get 1000 entries instead of one SQL query once, resulting in terrible performance), however, if you'd prefer stay within the bounds of ActiveRecord , you can use the form of where that takes arguments. 我倾向于在可能的情况下对更复杂的查询使用原始SQL,因为我发现它更容易控制行为(ORM有时可以完成一些不合需要的事情,例如执行相同的查询1000次以获取1000个条目,而不是一个SQL。查询一次,造成可怕的性能),但是,如果你的ActiveRecord的范围内停留喜欢,你可以使用的形式, where接受参数。 It'll be somewhat raw SQL, in that you need to specify the where clause yourself, but you won't need to get a raw_connection and explicitly execute -- it'll work within the framework of the ActiveRecord query you were doing. 这将是有点原始的SQL,因为您需要自己指定where子句,但是不需要获取raw_connection并显式执行-它可以在您正在执行的ActiveRecord查询的框架内工作。

So, that would look something like this: 因此,看起来像这样:

@locations = Location.where("location_type IN ('business', 'dispensary') OR
    (location_type = 'contact' AND owner_id = ?)", params[:id])

See this Active Record guide page for more info, section 2.2 . 有关更多信息,请参见此Active Record指南页面第2.2节

Edit in response to follow-up question from OP: 根据OP的后续问题进行编辑:

Regarding the ? 关于? in the SQL, you can think of it as a placeholder of sorts (there's really no formatting to be done with it, but rather signifies a parameter goes there). 在SQL中,您可以将其视为各种占位符(实际上并不需要进行格式化,而是表示其中有一个参数)。

The reason it's important is that when a ? 重要的原因是当? is placed in the query and then the actual value you want to use is passed as an argument to where (and certain other functions as well), the underlying SQL driver will interpolate the parameter into the query in such a way that prevents SQL injection , which could allow for all kinds of different problems. 放在查询中,然后将要使用的实际值作为参数传递给where (以及某些其他函数),底层S​​QL驱动程序将以防止SQL注入的方式将参数插入查询中,这可能会带来各种不同的问题。 If you were to instead do the interpolation yourself directly into the query string, you would still be potentially susceptible to SQL injection . 如果您要自己直接将其插值到查询字符串中,则仍然可能容易受到SQL注入的影响 So not only is ? 所以不仅是? safe from SQLI, it's specifically intended to prevent it. 从SQLI 安全 ,它是专门用于预防。

You can have a bunch of ? 你可以有一堆? in your query, as long as you pass the corresponding number of parameters as arguments after the query string (otherwise the SQL driver should error out). 在查询中,只要在查询字符串之后传递相应数量的参数作为参数(否则SQL驱动程序应该出错)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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