I wrote a below query class, which is throwing a missing attribute error which I didn't put in the select method anywhere. Any idea from where this error might be coming? Why project_id is being searched in the to_json method.
class WorkitemPriceResearchPresenter
def initialize(company)
#company = company
end
def query
#workitems ||= \
#company
.workitems
.joins(
:workitem_category,
:workitem_status,
{ project: [:shipyard, {vessel: :vessel_category}] },
)
.select <<-EOS
workitems.id as id,
projects.sequential_id as sequential_id,
vessels.name as vessel_name,
vessel_categories.code as vessel_category,
shipyards.name as shipyard,
workitems.item_code as item_code,
workitems.description as description,
workitems.unit as unit,
workitems.price_cents as price_cents,
workitems.currency as currency,
workitems.quantity as quantity,
workitem_statuses.name as status,
workitems.discount as discount,
DATE_PART('year', projects.scheduled_from::date) as scheduled_from_year,
projects.scheduled_from as scheduled_from,
DATE_PART('year', projects.scheduled_to::date) as scheduled_to_year,
projects.scheduled_to as scheduled_to,
workitem_categories.name as Category
EOS
end
def as_json
query.to_json
end
end
Error is:
pry(main)> WorkitemPriceResearchPresenter.new(company).query.as_json
Workitem Load (33.7ms) SELECT workitems.id as id,
projects.sequential_id as sequential_id,
vessels.name as vessel_name,
vessel_categories.code as vessel_category,
shipyards.name as shipyard,
workitems.item_code as item_code,
workitems.description as description,
workitems.unit as unit,
workitems.price_cents as price_cents,
workitems.currency as currency,
workitems.quantity as quantity,
workitem_statuses.name as status,
workitems.discount as discount,
DATE_PART('year', projects.scheduled_from::date) as scheduled_from_year,
projects.scheduled_from as scheduled_from,
DATE_PART('year', projects.scheduled_to::date) as scheduled_to_year,
projects.scheduled_to as scheduled_to,
workitem_categories.name as Category
FROM "workitems" INNER JOIN "workitem_categories" ON "workitem_categories"."id" = "workitems"."workitem_category_id" INNER JOIN "workitem_statuses" ON "workitem_statuses"."id" = "workitems"."workitem_status_id" INNER JOIN "projects" ON "projects"."id" = "workitems"."project_id" AND "projects"."deleted_at" IS NULL INNER JOIN "shipyards" ON "shipyards"."id" = "projects"."shipyard_id" AND "shipyards"."deleted_at" IS NULL INNER JOIN "vessels" ON "vessels"."id" = "projects"."vessel_id" AND "vessels"."deleted_at" IS NULL INNER JOIN "vessel_categories" ON "vessel_categories"."id" = "vessels"."vessel_category_id" AND "vessel_categories"."deleted_at" IS NULL WHERE "workitems"."deleted_at" IS NULL AND "workitems"."company_id" = $1 [["company_id", "c61e4368-1a60-464b-8002-9da31bf301e5"]]
ActiveModel::MissingAttributeError: missing attribute: project_id
from /Users/ar/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activerecord-4.2.11.3/lib/active_record/attribute_methods/read.rb:93:in `block in _read_attribute'
Let me know if I need to provide any more information.
Since you are joining workitems with project, your workitems is supposed to have a project_id attribute in order to join the tables. But it looks like you do not have such column, so you are getting this error.
Related
I have this code:
def self.by_vibe(vibe_id)
self.joins(:vibes).where(vibes: {id: vibe_id})
end
This code repeats (with some differences) all over my model, for example:
def self.by_music(music_id)
self.joins(:musics).where(musics: {id: music_id})
end
I have four or five of these, and thought of making just one and came out with something like this (for reference, hash contains {:vibes=>2}):
def self.by(hash)
self.joins(hash.keys.first).where(hash.keys.first.to_s => id = hash.values.first)
end
My self.by_vibe makes this query:
SELECT "bcls".* FROM "bcls" INNER JOIN "bcls_vibes" ON "bcls_vibes"."bcl_id" = "bcls"."id" INNER JOIN "vibes" ON "vibes"."id" = "bcls_vibes"."vibe_id" WHERE "vibes"."id" = $1 [["id", 2]]
And my second approach makes this:
SELECT "bcls".* FROM "bcls" INNER JOIN "bcls_vibes" ON "bcls_vibes"."bcl_id" = "bcls"."id" INNER JOIN "vibes" ON "vibes"."id" = "bcls_vibes"."vibe_id" WHERE "bcls"."vibe_id" = 2
How can I fix that where clause? Notice that the first one (the correct one is WHERE "vibes"."id" = $1 [["id", 2]] and the wrong one is WHERE "bcls"."vibe_id" = 2. It's asking for a different table.
You can get the first value as well as the first key:
def self.by(hash)
self.joins(hash.keys.first).where(
{ hash.keys.first.to_s => { id: hash.values.first } }
)
end
If you're only accepting one key value pair in your hash though it might be better to have two arguments to by:
def self.by(assoc, obj_id)
self.joins(assoc).where(assoc => { id: obj_id })
end
I just found the proper way of doing what I was trying to do.
def self.by(hash)
self.joins(hash.keys.first).where(hash.keys.first.to_s => {id: hash.values.first})
end
I have three models: company, event, event_space
company has many events
event belongs to event space
now I want to get all events from a company where the event_space has virtual attribute set to true
c = Comapny.first
c.events.joins(:event_space).where("event_space.virtual = true")
I'm doing something wrong because I have
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: event_space.virtual: SELECT "events".* FROM "events" INNER JOIN "event_spaces" ON "event_spaces"."id" = "events"."event_space_id" WHERE "events"."company_id" = 2 AND (event_space.virtual = true)
You can modify your where clause as follows to get it right:
c.events.joins(:event_space).where(event_spaces: {virtual: true})
I am following a railscast episode but I'm using postgresql and am getting a group_by error:
PG::Error: ERROR: column "ratings.created_at" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT created_at, sum(score) as total_score FROM "ratings" ...
^
: SELECT created_at, sum(score) as total_score FROM "ratings" WHERE ("ratings"."created_at" BETWEEN '2014-01-02 00:00:00.000000' AND '2014-01-23 13:43:06.187741') GROUP BY date(created_at)
How should I modify my code below to include group_by created_at
def self.chart_data(start = 3.weeks.ago)
total_votes = votes_by_day(start)
(start.to_date..Date.today).map do |date|
{
created_at: date,
total_score: total_prices[date] || 0
}
end
end
def self.votes_by_day(start)
ratings = where(created_at: start.beginning_of_day..Time.zone.now)
ratings = ratings.group("date(created_at)")
ratings = ratings.select("created_at, sum(score) as total_score")
ratings.each_with_object({}) do |rating, scores|
scores[rating.created_at.to_date] = rating.total_score
end
end
Your group by clause and your select clause have different attributes. If you're grouping by "date(created_at)" then you can no longer select "created_at."
def self.votes_by_day(start)
ratings = where(created_at: start.beginning_of_day..Time.zone.now)
ratings = ratings.group("date(created_at)")
ratings = ratings.select("date(created_at), sum(score) as total_score")
ratings.each_with_object({}) do |rating, scores|
scores[rating.created_at.to_date] = rating.total_score
end
In my controller, my filter_with_params() method is causing a syntax error in postgres when I try and stack will_paginate on top of it.
In my controller I call:
#styles = Style.filter_with_params(params).paginate(:page => params[:page], :per_page => 6)
Model method:
class Style < ActiveRecord::Base
def self.filter_with_params(params)
scoped = where("styles.item != ''")
if params[:t]
scoped = scoped.joins(:tags)
scoped = scoped.select("distinct styles.*, count(*) AS count")
scoped = scoped.where(tags: { name: params[:t] })
scoped = scoped.group('styles.id')
scoped = scoped.having("count(*) = #{params[:t].size}")
end
scoped
end
basically my filter method is looking for tags, and then i need to paginate on top of those results. Anyone with similar experience?
I'm using Rails 3 on this app
here is the postgres error
PG::Error: ERROR: syntax error at or near "distinct" LINE 1: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS...
^
: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" INNER JOIN "tags" ON "tags"."id" = "tagizations"."tag_id" WHERE "tags"."name" IN ('engagement') AND (styles.polenza_item != '') GROUP BY styles.id HAVING count(*) = 1
Your SQL has a problem. You need to say distinct clause before the count ('count(*) as count_all'). That is, once you remove the first call to the count function, it should work.
SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" ...
You can test your query in your rails console:
>> sql = "SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id..."
>> a = ActiveRecord::Base.connection.execute(sql)
>> a[0]
Hope this helps.
I have an sql query like this:-
SELECT * FROM `permissions` join entities where NOT EXISTS (select
entity_id,permission_id from role_permissions where role_id=5 and
entities.id = role_permissions.entity_id and permissions.id =
role_permissions.permission_id)
I would like to get the corresponding rails query.
I have tried this.
Permission.joins("join entities").joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id").select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id").group('role_permissions.entity_id,
role_permissions.permission_id')
But it doesn't works.
thanks
hari
I have been particularly in love with EXISTS queries lately, precisely because it does not require you to fully join another table. As far as I know, you do have to explicitly write the SQL clause, but you can still make it work with Activerecord. You can even put this in a scope within a lambda block.
Permission.joins(:entities).where(<<-SQL
NOT EXISTS(
select
* from role_permissions where role_id=#{your_role_id} and
entities.id = role_permissions.entity_id
and permissions.id = role_permissions.permission_id
)
SQL
)
Try like this for a default SQL query:
sql = "SELECT some_field FROM `permissions` join entities where NOT EXISTS (select entity_id,permission_id from role_permissions where role_id=5 and entities.id = role_permissions.entity_id and permissions.id = role_permissions.permission_id)"
results = ActiveRecord::Base.connection.execute(sql)
results.each do |result|
#register_users << { some_field: result[0] }
end
Try this
UPDATED BASED ON FIRST COMMENT
Permission.joins(:entities).joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id")
.select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id")
.group('role_permissions.entity_id, role_permissions.permission_id')