Home > Software engineering >  Ruby - IF or OR condition on a JOINS statement
Ruby - IF or OR condition on a JOINS statement

Time:06-11

How can I specify a OR condition on a joins statement? Basically I don't want the joins for where(:tenant_id => User.current_tenant. If I try OR condition I get the following error.

I get the following error.

Relation passed to #or must be structurally compatible. Incompatible values: [:joins] [catalog/explorer]

  scope :public_service_templates,                  ->         { joins(:miq_user_roles).where(miq_user_roles: { settings: nil}).or(where(:tenant_id => User.current_tenant)) }

CodePudding user response:

In rails 6, you can do the following:

scope :first_query, -> { joins(:miq_user_roles).where(miq_user_roles: { settings: nil }) }

scope :second_query, -> { where(:tenant_id => User.current_tenant)) }

scope :first_query_or_second_query, -> { first_query.or(self.second_query) }

Hope it helps

CodePudding user response:

The title says "IF" or "OR" so I am a bit unclear if you are looking for both templates where "miq_user_roles"."setttings" IS NULL OR "service_template"."tenant_id" = SOME_ID or if you are looking for "miq_user_roles"."setttings" IS NULL but if that is empty then return "service_template"."tenant_id" = SOME_ID.

Assumptions

  1. You are looking for the former combined OR condition
  2. The reasoning is that where(:tenant_id => User.current_tenant) may not have a relationship with MiqUserRole and thus the join prohibits the return of the appropriate values.

If so just use left_joins instead of joins.

This will create an outer join and will make this part (miq_user_roles: { settings: nil}) of the condition non impactful on this part where(:tenant_id => User.current_tenant)); however you will still have to add the left_joins to the second condition for structural compatibility. e.g.

scope :public_service_templates,-> { 
  left_joins(:miq_user_roles)
   .where(miq_user_roles: { settings: nil})
   .or(left_joins(:miq_user_roles)
       .where(:tenant_id => User.current_tenant))
}

Alternatively you could use Arel for the condition which will allow the OR to be part of the single where clause (without needing to merge scopes) e.g.

scope :public_service_templates,-> {
  left_joins(:miq_user_roles)
    .where(
       MiqUserRole.arel_table[:settings].eq(nil).or(
         arel_table[:tenant_id].eq(User.current_tenant.id)
       )
    )
}

Additionally not sure what User.current_tenant returns. Depending on implementation you need to pass an instance of User to this call e.g.

scope :public_service_templates,->(user) {#...

then you would call as ServiceTemplate.public_service_templates(user)

  • Related