After upgrading my rails app from 3.2 to 4.1.13 one of my queries doesn't seem to be making aliased columns available to ActiveRecord (I think). If I run .to_sql and query using that SQL I can clearly see the aliased columns are being returned but when I try to access them like I used to I get undefined method errors.
I'm not sure how to troubleshoot this.
The query is built from a Ransack search and some Squeel joins.
search_result = search.result.in_current_club_type.
joins{role.outer}.joins{contact.outer}.for_current_or_last_year.with_fellowship.
select(<<-SQL
people.id, people.last_name, people.first_name, people.parent_only, clubs.name AS club_name,
roles.name AS role_name, tlt, master_guide, pla, grade, people.type, people.email,
contacts.primary_phone AS phone
SQL
)
The aliases I'm needing to access are role_name, club_name, and phone. I've placed a binding.pry right after that and attempt search_result.first.role_name and the returned error is
NoMethodError: undefined method `role_name' for #<Member:0x007fa8bcf121d0>
I could turn those into instance methods, but I'd like to be able to continue with the existing way of doing things if possible.
Thank you for your guidance.
Ok, I don't know exactly why but it seems that search was being built from a scope that needed to be rewritten using Squeel syntax. Then things joined properly and I could call the aliased columns.
Old Scope
scope :unapproved, -> { joins(approvals).where('approvals.approved IS NULL OR approvals.approved = ?', false) }
New Scope
scope :unapproved, -> { joins{approvals}.where{(approvals.approved == nil) | (approvals.approved == false)} }
Related
I am looking for the way to execute MySQL statement checking if given parameter exists. As I remember I can do the following in Oracle to achieve that:
select s.* from Site s
where s.study = :study
and (:enabled is null or s.enabled = :enabled)
is anything like that possible in MySQL too? The same code executes without error but never return any records.
My goal here is to avoid multiple lfs and elses in my java code. It should work the way that the query looks like that when enabled parameter is null:
select s.* from Site s
where s.study = :study
and like that if the parameter is not null:
select s.* from Site s
where s.study = :study
and s.enabled = :enabled
and I want to do that with a single query
I believe this is what you are asking:
SELECT s.* from Site s
WHERE s.study = "some_study"
AND (s.enabled IS NULL OR s.enabled = '' OR s.enabled = "enabled");
Unfortunately it is highly dependent on database driver. My initial query works when run in database tools but doesn't have to when it comes to run it by JPA. So I'm to close this question as it doesn't require further answers. I'm sorry lads for wasting your time.
I'm using Cakephp 3 using sqlserver as datasource server. I am sure there's no problem with my database connection.. as home.ctp prompts that I am connected to my database.. and I'm as well using migrations plugin to create my tables.. it seems like there is no problem working with these tools. but after I bake my MVC, I only got page full of errors..
for example
$bin\cake bake all tests
there are no errors I found and MVC are in its specific folder, testController.php, testTable, etc.
and in browsers
localhost:8765\tests
but all I got is page of different errors.. Im seeing
Error: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near the keyword 'desc'.
SELECT * FROM (SELECT Tests.id AS [Tests__id], Tests.desc AS [Tests__desc], (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) AS [_cake_page_rownum_] FROM tests Tests) _cake_paging_ WHERE _cake_paging_._cake_page_rownum_ <= :c0
and more errors on the left side.
I assume this is because of controllers with wrong queries or queries generated by bake is for mysql only. I just wanna know how to deal with this. is there a setting I forgot to do? please advice. I am new to Cakephp, and English is not my native language, sorry if I can't explain my question properly. thanks in advance.
As already mentioned by Vishal Gajjar in the comments, you are using the reserved keyword desc for your column name, hence the error, it's not bakes fault, it's yours.
In order to be able to use such reserved words, the column name needs to be quoted properly, however CakePHP 3 doesn't auto-quote by default anymore, as it's an expensive operation.
If you insist on using reserved words, enable identifier quoting via the quoteIdentifiers option in your app.php config, or enable it manually using the autoQuoting() (enableAutoQuoting() as of CakePHP 3.4) method of the DB driver.
See also
Cookbook > Database Access & ORM > Database Basics > Identifier Quoting
Cookbook > 3.x Migration Guide > New ORM Upgrade Guide > Identifier Quoting Disabled by Default
API > \Cake\Database\Driver::autoQuoting()
API > \Cake\Database\Driver::enableAutoQuoting()
You can use this code before problematic query:
$this->Tests->connection()->driver()->autoQuoting(true);
and when you are finished you can turn auto quoting off:
$this->Tests->connection()->driver()->autoQuoting(false);
So bad performance would be only on problematic query.
Use this :
SELECT * FROM (SELECT Tests.id AS [Tests__id], Tests.[desc] AS [Tests__desc],
(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) AS [_cake_page_rownum_] FROM tests Tests) _cake_paging_
WHERE _cake_paging_._cake_page_rownum_ <= :c0
If you do use a keyword, use it in square braces [ ]
Switching a rails app from MySQL to Postgres gives the following error:
ERROR: column "contacts.id" must appear in the GROUP BY clause or be used in an aggregate function
Here is the scope in question:
class User < MyModel
def self.top_contacts(timeframe = 1.week.ago, limit = 5)
Contact.unscoped
.where('created_at between ? and ?', timeframe, Time.now)
.group(:user_id)
.order('sum(score) DESC')
.limit(limit)
.includes(:user)
.collect{|x| x.user}
end
end
How to fix this?
Isn't using Rails as the database abstraction layer ensure switching the database should work seamlessly?
The problem is on the level of the SQL, which is invisible from your ORM layer. The problem is exactly with the RoR ORM, because it seems to generate a MySQL-friendly query which uses an extraordinary feature of the MySQL, which postgresql don't have.
The quick solution: give contacts.id to the columns by which you are GROUP-ing as well:
.group("user_id, contacts.id");
I have a model with a has_many relationship, and a scope to determine whether or not it has any children, such as:
scope :with_nomination, :include => [:nomination], :conditions => "nominations.service_id IS NOT NULL"
Using this, I can do something like Service.with_nomination and receive a list of all services with nomination children.
The problem is that when I do something like Service.select("id, firstName, lastName").with_nomination ActiveRecord in essense does a SELECT * FROM services which is very bad and does not utilize the indexes I so painstakingly set up.
How can I either rephrase my query or modify my scopes to work with the .select() command?
Turns out in the syntax I was using, a select is not possible, so it does a select * and any further selects are already overriden.
I re-wrote the scopes like so:
scope :no_nomination, joins("LEFT JOIN nominations ON nominations.service_id = services.id").where("nominations.service_id IS NULL")
# important distinction here, the left join allows you to find those records without children
scope :with_nomination, joins(:nomination).where("nominations.service_id IS NOT NULL")
Using this syntax allows me to do something like Service.select(:id,:user,:otherfield).with_nomination
8 years later...
This is ugly, but you could also convert the resulting ActiveRecord::Relation into to sql with to_sql and run the command manually with ActiveRecord::Base.connection.execute.
It might look like this:
query = Service.select("id, firstName, lastName").with_nomination.to_sql
records = ActiveRecord::Base.connection.execute(query)
records.first["firstName"] # => First Name
This doesn't eliminate the excess columns that the scope retrieves, and you have to access each field with string keys, but hey, at least you can still access them!
I'm building a search feature for my Symfony2 project, and I wrote the SQL for it as follows:
SELECT dlc.title, dlc.description, dlc.keywords
FROM ShoutMainBundle:Dlc dlc
WHERE MATCH (dlc.title, dlc.description, dlc.keywords) AGAINST (":keyword" IN BOOLEAN MODE)
AND dlc.type = (":audio")
ORDER BY dlc.date DESC
However, when I run this in the project the following error is given:
[Syntax Error] line 0, col 96: Error: Expected known function, got
'MATCH'
Is there an alternative I could use instead of MATCH? At the moment (just so I can do basic testing) I'm using LIKE, but it doesn't work too well if it's more than one word being used to search with.
EDIT:
This is how the code is used within the code:
$em = $this->getDoctrine()->getEntityManager();
$wckeyword = '%'.$skeyword.'%';
$dlcresult = $em->createQuery('
SELECT dlc.title, dlc.description, dlc.keywords
FROM ShoutMainBundle:Dlc dlc
WHERE MATCH (dlc.title, dlc.description, dlc.keywords) AGAINST (":keyword" IN BOOLEAN MODE)
AND dlc.type = (":audio")
ORDER BY dlc.date DESC'
)->setParameters(array('type' => $stype, 'keyword' => $wckeyword));
$dlcres = $dlcresult->getResult();
Doctrine doesn't support that out-of-the-box, true. But you can:
Create custom functions for DQL yourself
Use native SQL and custom hydration
This is not currently possible with Doctrine2 ORM. As Doctrine supports many different database vendors and most of them don't have a FULLTEXT search feature, it's not supported at all.
You can always use Doctrine2 DBAL for searching. You lose all these nifty orm features, but in my practice they aren't that needed in searching situations anyway.