Rails - model relations from custom column - ruby-on-rails-3

Having an example of 2 models as follow:
Model 1
column 1 --- column 2 --- column 3
id --- fb_id --- someOtherThing
Model 2
column 1 --- column 2 --- column 3
id --- fb_id --- someOtherThing
Where for example, fb_id is the Facebook ID as big int.
How can I construct a relation (for example belongs_to) from column 2 of the first model to column 2 of the second model?
For the moment I have do something like this:
model 1:
belongs_to :model2, :foreign_key => 'fb_id'
But how can I pre-select the column from model 1 (column 2) that must match the second model's column? (I think that in this manner it takes column 1 from model 1).
In synthesis:
How to create a relation (belongs_to or has_many) model1(:fb_id) => model2(:fb_id)
and not model1(:id) => model2(:fb_id)

If I understood correctly what you need is to retrieve a record with a valid association, right?
You can do that using the following:
Model1.joins(:model2 => :fb_id)
This will retrieve only the Model1' that have a valid association!

Related

Rails 6 How to find element where association count is less than 2

I have a problem with extracting data with one query. My two models looks like that:
# school.rb
class School < ActiveRecord::Base
has_many :meetings
end
# meetings.rb
class Meeting < ActiveRecord::Base
belongs_to :school
belongs_to :user
# fields
# status: [accepted, not_accepted, finished]
en
I want to take every school where passed User has less than 2 meetings with status finished. I was trying something like this:
School.joins(:meetings).where(meetings: { user: User, status: 'finished' }).group(:id).having( 'count(meetings.id) < 2')
But it works if User has one finished meeting in each school. I wonder if it is possible to solve this with one query? Maybe some of you knows if it is possible to do this and how?
#Edit
An example for easier understanding of what I would like to receive:
School | User | Meeting
1. A | Adam | finished
2. A | Adam | accepted
3. A | Adam | finished
4. B | Adam | accepted
5. C | John | finished
6. D | - | -
7. E | John | finished
So I want to create query which will returns school B, C, D and E for user Adam
I think you need to reverse your thinking here: get the schools you want to EXCLUDE from the results instead of trying to add extra ones to your query. Something like this:
# Get schools with more than 1 meeting for the user
excluded_schools = School.joins(:meetings)
.where(meetings: { user: User, status: 'finished' })
.group(:id)
.having('count(meetings.id) > 1')
# Get ALL schools except for the ones you didn't want
filtered_schools = School.where.not(id: excluded_schools.select(:id))
Using select(:id) instead of pluck(:id) avoids triggering a new database query, so all of this should take just 1 database query when used inside a method. Of course in the console you'll have to nest these instead of storing in variables if you want to accomplish everything in 1 query.

Selecting rows using multiple LIKE conditions from a table field

I created a table out of a CSV file which is produced by an external software.
Amongst the other fields, this table contains one field called "CustomID".
Each row on this table must be linked to a customer using the content of that field.
Every customer may have one or more set of customIDs at their own discretion, as long as each sequence starts with the same prefix.
So for example:
Customer 1 may use "cust1_n" and "cstm01_n" (where n is a number)
Customer 2 may use "customer2_n"
ImportedRows
PKID CustomID Description
---- --------------- --------------------------
1 cust1_001 Something
2 cust1_002 ...
3 cstm01_000001 ...
4 customer2_00001 ...
5 cstm01_000232 ...
..
Now I have created 2 support tables as follows:
Customers
PKID Name
---- --------------------
1 Customer 1
2 Customer 2
and
CustomIDs
PKID FKCustomerID SearchPattern
---- ------------ -------------
1 1 cust1_*
2 1 cstm01_*
3 2 customer2_*
What I need to achieve is the retrieval of all rows for a given customer using all the LIKE conditions found on the CustomIDs tables for that customer.
I have failed miserably so far.
Any clues, please?
Thanks in advance.
Silver.
To use LIKE you must replace the * with % in the pattern. Different dbms use different functions for string manipulation. Let's assume there is a REPLACE function available:
SELECT ir.*
FROM ImportedRows ir
JOIN CustomIDs c ON ir.CustomID LIKE REPLACE(c.SearchPattern, '*', '%')
WHERE c.FKCustomerID = 1;

Querying a has_many association's count in Rails 3

I've been going over a tonne of StackOverflow articles trying to work out a particularly tricky Rails 3 join query to no avail - so I'm asking a new question!
I have a model called "User" which has_many "Checks" via a polymorphic association (the actual columns on Check are "target_type" and "target_id"). The Check has a string column called "type", which denotes the reason for the check. Something like this:
-----------------------------------------------------
id | target_type | target_id | type |
-----------------------------------------------------
1 User 1 type_1
2 User 2 type_2
I want to find all users who don't have a check associated with them with a set type - so it's a join and a count, I think.
So for instance, I want to be able to make a query to find all users who have no "type_1" checks, and it should return the user with id #2.
How would I go about doing this?
(I've been looking at all the stuff around counts and grouping (e.g. Rails has_many association count child rows) but nothing seems to quite match.)
Thanks!
You can try sth like:
class Merchant < ActiveRecord::Base
...
def self.non_fraudulent
includes(:fraud_checks).group("#{self.table_name}.id").having("SUM(CASE WHEN fraud_checks.type = 'fraudulent_ip' THEN 1 ELSE 0 END) = 0")
end
end

Zend JOIN clause return as array in the object?

I currently am using the following code
$select = $this->select()
->setIntegrityCheck(false)
->from(array('st' => $this->_name))
->join(array('sp' => 'staff_permissions'), 'sp.staff_id = st.id and sp.pool_id = ' . $pool_id )
->join(array('p' => 'permissions'), 'p.id = sp.permission_id')
->where('staff_id = ?', $staff_id);
return $this->fetchAll($select)->toArray();
It combines three tables and returns the result. The 'st' table corresponds to one staff (so one row), and the other two tables correspond to multiple rows. So what I was hoping was to get a single object back such that the other two tables are arrays inside the object.
So as an example, I get back $row, so that $row->first_name is the name, but $row->permission_id is an array with all the ids in it.
Can that be done using the JOIN clause?
This query should be done in the lowest layer in your application, the next layer up the stack will be your mappers. In your mapper layer you can map to your Entities, which will be a 'staff' entity (object) which contains a collection for 'staff_permissions' & a collection for 'permissions'
model diagram:
-----------
| service | // business logic
-----------
|
-----------
| mapper | // maps external data to internal entities (or vice versa)
-----------
|
----------- ----------------------
|dao (sql)| -> | zend table gateway |
----------- ----------------------
mapper example code:
$staffEntity = new StaffEntity();
$staffEntity->setName($response['name']);
foreach($response['staff_permissions] as $permission) {
$permission = new Permission();
$permission->setName($permission['name']);
$permission->setRule($permission['rule']);
// ... etc ...
$staffEntity->addPermission($permission);
}
// ... same for permissions ...
return $staffEntity;

Count and Select Object in ActiveRecord with 1 query

We have objects that we want to represent in stacks (think of stacking items in an MMO). There will be duplicate rows.
Let's say our owned_objects table looks like this.
user_id | object_id
1 | 27
1 | 27
3 | 46
3 | 46
5 | 59
I want the query to do
SELECT
user_id,
object_id,
count(*) AS count
FROM owned_objects
GROUP BY
user_id,
object_id;
And return either the 3 distinct OwnedObjects (or even just getting the distinct Objects would work too) and a count associated with it.
I know this is possible with SQLAlchemy, but can you do it with ActiveRecord?
How about …
#objects = user.objects.all(:select => "count(*) as count, objects.*", :group => :object_id)
… or similar?
You can then retrieve the counts by a dynamically created attribute on each object:
#object.first.count # the "stack depth" of the first object.
This assumes either a has_and_belongs_to_many :objects or a has_many :objects, :through => :owned_objects on user.
Found a solution, but not sure if it's the cleanest (hope it isn't).
Basically I created a SQL view that does that query and created a model for it. There's a plugin for rails that recognizes views on migrations.