Here is the sceanrio:
I'm using CanCan gem and try to implement a :read ability accompanied with 2 AND conditions
can :read, Truck, :product => {:company_id => user.company_id}
Now here I wanted to have and additional condition checking for a column value as follows:
can :read, Truck, :product => {:company_id => user.company_id, :category_id => user.category_id}
But the above statement throws error in active_adapter saying "Undefined table_name for nil class"
Also the second set of condition category_id needs to be present only if a flag "check_category_id_flag" is checked. At the end I want something as below to work for me:
can :read, Truck, :product => {:company_id => user.company_id,
( user_role.check_category_id_flag? ? :category_id => user.category_id : 1 == 1)}
You can combine conditions like this
can :read, Truck do |truck|
truck.product.company == user&.company && truck.product.category == user&.category
end
Related
I am experiencing slow performance on a rake task. Upon review, it looks like the same item is being queried 3 times. Is there a way to simplify this so only one query is executed? Would this have a significant performance improvement? Would love to hear your ideas.
Here's a breakdown...
So I check if it exists:
if Ecommerce.exists?(:legacy_id => legacy_id, :company => company)
Then the same item is queried again to pluck a value needed:
historical_interest = Ecommerce.where(:legacy_id => legacy_id, :company => company).pluck(:interest)
Then if the plucked value is different, the record is updated:
if interest != historical_interest
Ecommerce.where(:legacy_id => legacy_id, :company => company).update_all(:interest => interest, :end_date => end_date, :revenue => revenue)
end
else
#other stuff
Full code:
if Ecommerce.exists?(:legacy_id => legacy_id, :company => company)
# It exists.
historical_interest = Ecommerce.where(:legacy_id => legacy_id, :company => company).pluck(:interest)
# Another statement to check that the Interest != UnitSold
if interest != historical_interest
Ecommerce.where(:legacy_id => legacy_id, :company => company).update_all(:interest => interest, :end_date => end_date, :revenue => revenue)
end
else
#other stuff
this should help a little:
ecommerce_array = Ecommerce.where(legacy_id: legacy_id, company: company)
if ecommerce_array.any?
historical_interest = ecommerce_array.pluck(:interest)
return unless interest == historical_interest
ecommerce_array.update_all(....)
else
#....
EDIT:
change this historical_interest = ecommerce_array.pluck(:interest) into this historical_interest = ecommerce_array.collect(&:interest)
I'm in the middle of migrating to Rails 3. I think I finally got everything working in testing and development but now in production (actually in staging, that environment Rails doesn't believe exists) a certain query doesn't work. It seems like :joins is now ignored.
class Organisation
# Maybe this is relevant, because it has :dongle in it too.
LICENCE_TABLE_INCLUDES = [:organisation, :user, :owner_organisation, :profile, :dongle,
{:nested_licences => [:profile]} ]
has_many :dongles
def latest_received_licences_for_each_dongle
Licence.find(:all,
:joins => [:dongle],
:include => LICENCE_TABLE_INCLUDES,
:conditions => { 'dongles.organisation_id' => id },
# :group => 'dongles.id', # broken
:order => 'dongles.name ASC, licences.created_at DESC').
group_by {|l| l.dongle.name}.
sort_by {|d,ls| d}.
map {|d,ls| ls[0]}
# Tried to modernise it a little - same results.
#Licence.
# joins(:dongle).
# includes(LICENCE_TABLE_INCLUDES).
# where(:dongles => { :organisation_id => id }).
# order('dongles.name ASC, licences.created_at DESC').
# group_by {|l| l.dongle.name}.
# sort_by {|d,ls| d}.
# map {|d,ls| ls[0]}
end
end
class Dongle
has_many :licences
belongs_to :organisation
end
class Licence
belongs_to :dongle
end
Calling this results in an error:
Mysql2::Error: Unknown column 'dongles.organisation_id' in 'where clause': SELECT `licences`.* FROM `licences` WHERE `licences`.`parent_licence_id` IS NULL AND ((`dongles`.organisation_id = 143)) AND (`licences`.parent_licence_id IN (22,23))
mysql2 (0.2.18) lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `query'
As you can see, it hasn't added the join into the query. (rails 3.0.17, mysql2 0.2.18 - not updating to Rails 3.2 yet as I'm trying to get 3.0 to work first.)
I am working on a Rails 2.3.9 app and my question involves both a self referencial relationship and a named_scope. This application allows users to log and share workouts. A workout can be public or private and that is designated by #workout.public == 1.
I allow users to 'follow' people. So on a current_user's dashboard I display all public workouts from users that current_user follows with the following code:
/dashboard/index.html.erb
<% current_user.friends_workouts.each do |workout| %>
<%= link_to (workout.title), workout %> <br/>
by <%= link_to (workout.user.username), workout.user %> - <%= time_ago_in_words(workout.created_at)%> ago</p>
<% end %>
user.rb
def friends_workouts
#friends_workouts ||= Workout.current.public_workouts.find_all_by_user_id(self.friends.map(&:id), :order => "created_at DESC", :limit => 3)
end
workout.rb
named_scope :public_workouts, :conditions => {:public => 1 }, :order => "created_at DESC"
I now want to add a condition to this scope as I am adding another level of sharing. Users can associate to a "box" (a gym really) through a "membership" model. So if the current_user belongs_to the same "box" as a user they follow, they should not only see the workouts marked public but also workouts where #workout.box_only == 1.
How can I affect the above to include all public workouts from followed users AND workouts from followed users where #workout.box_only == 1 and #workout.user.membership.box_id == current_user.membership.box_id. I know that syntax is incorrect but you get my point (hopefully).
UPDATE:
It also needs to be considered that :public_workouts is being called from pages that don't require a logged_in? user so in that case if the scope is trying to reference current_user it will throw an error.
UPDATE 2:
:user has_many :memberships
I believe something like the following should do it for you:
named_scope :public_workouts,
:joins => ", user, membership"
:conditions =>
"workouts.public = 1 or
membership.box_id = #{current_user.membership.box_id}",
:group => "workouts.id",
:order => "workouts.created_at DESC"
You would have to play around with this for a bit. The hard part every time I try something like this is to get the OR conditions correct. You want to get all public and those where the joined membership.box_id matches regardless of public being 1.
Edit: Admittedly this is perhaps not the most ruby way of building a query and I haven't tested it properly but something like below could also be made to work.
def self.public_workouts
query = Workout.joins(:user => { :membership })
if current_user
query.where('memberships.box_id = ? or workouts.public = 1', current_user.membership.box_id) unless current_user.membership.box_id.nil?
else
query.where('workouts.public = 1')
end
query.group('workouts.id')
query.order("workouts.created_at DESC")
return query
end
Edit2
Another alternative could be to create two separate scopes and create a class method that combines the two scopes. This class method would then be used in the view.
named_scope :box_workouts,
:joins => ", user, membership"
:conditions => "memberships.box_id = #{current_user.membership.box_id}"
:group => "workouts.id",
:order => "workouts.created_at DESC",
:select "workouts"
named_scope :public_workouts,
:conditions => :public => 1
:order => "workouts.created_at DESC"
def self.public_box_workouts
return box_workouts.merge(public_workouts).limit(3) if current_user
return public_workouts.limit(3)
end
Edit3 Not so hard, I believe something like below will work.
def self.box_and_public_workouts(user)
return public_workouts if user.nil? or user.memberships.blank?
return public_workouts + box_workouts(user.memberships.map(&:box_id))
end
named_scope :box_workouts, lambda { |box_ids| { :conditions => ['box_id IN (?)', box_ids], :order => 'created_at DESC' } }
Apologies for taking so long. I was missing confused with how the "old" way of querying the database. I went right for Rails3 :)
Anyway, I didn't want to commit anything so I tried to fork it to send a pull request but github is being rude to me tonight. Might just copy from here then.
For example, say I have something like BlogCategory which has a HABTM with BlogPost, and I want to select only the BlogCategories that have actually been used in a BlogPost
named_scope :published, {
:include => :blog_posts,
:select => 'blog_categories.*, count(blog_posts.id) as post_count',
:group => 'blog_categories.id having post_count > 0',
:conditions => 'blog_posts.published = 1',
}
Problem I'm having is that the :select part of this seems to be getting completely ignored by rails, so the count field doesn't get put into the query, and I end up with the error "Unknown column 'post_count' in 'having clause'"
I don't know why it doesn't recognize post_count but it should work with:
:group => 'blog_categories.id having count(blog_posts.id) > 0',
For several hours now I am unsuccessfully trying to get sphinx scopes work.
I want to scope tags of ActsAsTaggableOn. In my model (that is taggable) I tried the following scopes:
# This normal scope works
scope :tagged, lambda {
joins(:taggings => :tag).
where("tags.name = 'consequatur'")
}
# fails! (can't convert ActiveRecord::Relation into Hash)
sphinx_scope :tagged do
joins(:taggings => :tag).
where("tags.name = 'consequatur'")
end
Another try with the old conditions:
# works with normal scope (returns one record)
scope :tagged, :joins => :taggings, :conditions => {"taggings.tag_id" => 74}
# fails! (returns nothing)
sphinx_scope(:tagged) do
{:joins => :taggings, :conditions => {"taggings.tag_id" => 74}}
end
How can I make those scopes work? Is there another way to archive that task? I want to only search those models that are tagged with a specific tag.