Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use left joins instead of inner join when searching #1581

Merged
merged 1 commit into from
Sep 21, 2020

Conversation

samnang
Copy link
Contributor

@samnang samnang commented Mar 23, 2020

When searching an association with belongs_to :foobar, optional: true, the current implementation uses INNER JOIN which will filter out resources where the association does not exist.

By default when searching associations, it should LEFT OUTER JOIN the association.

@sedubois
Copy link
Contributor

The tests throw NoMethodError: undefined method 'left_joins' for #<ActiveRecord::Relation []>.

@samnang
Copy link
Contributor Author

samnang commented Mar 25, 2020

Oh, I didn't notice the left_joins is only supported since the Rails 5, so we need to have a conditional check for the Rails version. If it's still on Rails 4, we need to find a way to dynamic generating the left joins query string from those associations. I tried to access attribute_types[:association_name], but I couldn't find a way to get primary_key and foreign_key options, is there any way to access those options?

@sedubois
Copy link
Contributor

@pablobm should Rails < 5 be dropped from the appraisal as it's EOL?

@nickcharlton nickcharlton added models models, associations and fetching the underlying data search finding things through our models labels Mar 26, 2020
@nickcharlton
Copy link
Member

I'm sort of averse to dropping Rails <5 support just yet, and it wouldn't be something I'd want to do in this PR. I've opened #1588 for that bit.

@pablobm
Copy link
Collaborator

pablobm commented Apr 2, 2020

Duplicate of #1386

@pablobm
Copy link
Collaborator

pablobm commented May 8, 2020

@samnang - A way to retrieve association keys would be using the reflection API. For example:

> Order.reflect_on_association(:line_items).foreign_key
=> "order_id"

This also works on scopes:

> Order.where(address_state: 'NY').reflect_on_association(:line_items).foreign_key
=> "order_id"

Having said that, we may end up dropping support for Rails <5 in the next few months (see #1588), so this solution may not live long... or will it?

@pablobm
Copy link
Collaborator

pablobm commented May 8, 2020

Also reported at #1637, which includes a detailed description of the issue.

@samnang
Copy link
Contributor Author

samnang commented May 8, 2020

@samnang - A way to retrieve association keys would be using the reflection API. For example:

> Order.reflect_on_association(:line_items).foreign_key
=> "order_id"

This also works on scopes:

> Order.where(address_state: 'NY').reflect_on_association(:line_items).foreign_key
=> "order_id"

Having said that, we may end up dropping support for Rails <5 in the next few months (see #1588), so this solution may not live long... or will it?

Thanks for the response. I think we better to wait instead of introducing complexity by using reflection to construct left join for all tables to join.

@livedo
Copy link
Contributor

livedo commented Jul 14, 2020

@nickcharlton, instead of just waiting, would you be open to merging a version with essentially .send(Rails::VERSION::MAJOR >= 5 ? "left_joins" : "joins", tables_to_join) for the time being?

@pablobm
Copy link
Collaborator

pablobm commented Jul 18, 2020

@livedo, I would be ok with that, with small changes.

Instead of detecting the Rails version, I'd prefer respond_to?(:left_join). Also I'd file this away into a dedicated, self-describing function. Something like this:

    def search_results(resources)
      inner_or_left_joins(resources, tables_to_join).
        where(query_template, *query_values)
    end

    def inner_or_left_joins(left, right)
      # ActiveRecord::QueryMethods#left_join is not supported with Rails 4 and below
      if left.respond_to?(:left_join)
        left.left_joins(right)
      else
        left.joins(right)
      end
    end

@nickcharlton
Copy link
Member

I second @pablobm's suggestion. I'll also say that now the 0.14.0 release is out, removing support for Rails 4 is something we'll be looking at soon and we can likely merge this branch broadly as is.

So if it's something we can avoid working around, I'd recommend patching your current install instead of us merging that.

@pablobm
Copy link
Collaborator

pablobm commented Sep 10, 2020

As @nickcharlton says, my suggestion is not relevant any more, since we have dropped support for Rails 4.

@samnang - Would you be able to correct the lint warnings (as raised by Hound)?

@nickcharlton - Would you be ok to merge this, given the above?

When searching an association with belongs_to :foobar, optional: true, the
current implementation uses INNER JOIN which will filter out resources where
the association does not exist.

By default when searching associations, it should LEFT OUTER JOIN the
association.

This feature is supported from Rails 5 onwards.
@nickcharlton nickcharlton merged commit 4207c9d into thoughtbot:master Sep 21, 2020
@nickcharlton
Copy link
Member

Thanks for your work on this!

G-Rath added a commit to ackama/nzsl-share that referenced this pull request May 27, 2021
G-Rath added a commit to ackama/nzsl-share that referenced this pull request Jun 7, 2021
* feat: update `administrate`

* fix: use `searchable_fields` instead of `searchable_field`

thoughtbot/administrate#1203

* fix: remove `nil` values when listing tables to join

thoughtbot/administrate#1581
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
models models, associations and fetching the underlying data search finding things through our models
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants