Rails admin gem, polymorphic association - ruby-on-rails-3

How to get the queried data having polymorphic association
I have an 3 models
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :pictures, as: :imageable
end
class Product < ApplicationRecord
has_many :pictures, as: :imageable
end```
Employee and Product have column **is_active**.
In rails admin dropdown. I want to display the data where employee and product is **is_active = true.**
Have tried multiple ways to achieve this.
Please let me know if there is any solution?

You can write a custom scope in picture model as below
scope :list_active(imageable_type), -> {
where(imageable_type: imageable_type)
.joins("INNER JOIN #{imageable_type.pluralize} ON
{#imageable_type.pluralize}.id = imageable_id AND
imageable_type = '#{imageable_type}'")
.where('#{imageable_type.pluralize}.is_active = ?', true)
}
Then you can simply list and use the response.
E.g result = []
result << Image.list_active('Employee')
result << Image.list_active('Product')

Related

Rails ActiveRecord querying

So I have the following three models: Assignment.rb, Submission.rb, User.rb
And here are the relationships:
class Assignment
has_many :submissions
end
class Submission
belongs_to :assignment
belongs_to :user
# submission has a boolean column called submitted with val true or false
end
class User
has_many submissions
end
I want to know how can I query the assignments that a user has not submitted (in a clean way)? If a user submits an assignment, a new submission for that assignment and user will be created.
Not sure if I provided enough info for anyone to answer, so please comment if anything else is needed.Thx!
The logic that #Norly Canarias is using is correct, but I would alter it to use methods on the User class, and I would also modify it to make it database-agnostic (for example, using 'submissions.submitted = true' will not work at all in Postgres).
class User < ApplicationRecord
has_many :submissions
has_many :assignments, through: :submissions
def submitted_assignments
assignments.where(submissions: {submitted: true})
end
def unsubmitted_assignments
Assignment.where.not(id: submitted_assignments)
end
end
I have tested this and it works as expected. For a user who has a Submission for Assignment 1 with submitted == true, and who has a Submission for Assignment 2 with submitted == false, and assuming there are two more Assignments (3 and 4) for which no Submission exists, you will get:
>> user.submitted_assignments.ids
#=>[1]
>> user.unsubmitted_assignments.ids
#=>[2, 3, 4]
I think something like this could work (I haven't tested though):
class Assignment
has_many :submissions
end
class Submission
belongs_to :assignment
belongs_to :user
end
class User
has_many :submissions
has_many :assignments, through: :submissions
end
user = User.first
submitted = user.assignments.where('submissions.submitted = true')
not_submitted = Assignment.where.not(id: submitted)
You can also make it a scope
class Assignment
has_many :submissions
scope :not_submitted_by_user, ->(user) do
where.not(id: user.assignments.where('submissions.submitted = true'))
end
end
user = User.first
not_submitted = Assignment.not_submitted_by_user(user)
To get all the Assignments that are not from a specific user
#assignments = Assignment.where.not(user_id: user_id)
A clean way to do it is to create a scope in the Assignment Model
class Assignment
has_many :submissions
scope :not_from_user, ->(user_id) {where.not(user_id: user_id) }
end
And then calling
#assignments = Assignment.not_from_user 1

ActiveRecord query based on multiple objects via has_many relationship

I have a Product class that has_many Gender through Connection class instances. I want to query to find products that have both end_a and end_b present. The current class method works with 2 caveats:
Fails to return correctly if searching where end_a and end_b are the same. Instead should search if product has 2 instances, not just one of object.
Returns an Array when I want an ActiveRecord_Relation.
The class method .query is below, any feedback or ideas are appreciated.
class Product < ActiveRecord::Base
has_many :connections, dependent: :destroy, as: :connectionable
has_many :genders, through: :connections
def self.query(end_a, end_b)
search_base = active.joins(:connections)
end_a_search = search_base.where(connections: { gender_id: end_a } )
end_a_search & search_base.where(connections: { gender_id: end_b } )
end
end
ps: Once this is figured out will likely move this to a scope for Product
class Product < ActiveRecord::Base
has_many :connections, dependent: :destroy, as: :connectionable
has_many :genders, through: :connections
scope :with_genders, -> (end_a, end_b) {
relation = joins('INNER JOIN connections c1 ON c1.connectionable_id = products.id AND c1.connectionable_type = \'Product\'')
.joins('INNER JOIN connections c2 ON c1.connectionable_id = c2.connectionable_id AND c2.connectionable_type = \'Product\'')
.where(c1: {gender_id: end_a}, c2: {gender_id: end_b})
.group('products.id')
end_a == end_b ? relation.having('COUNT(products.id) > 1') : relation
}
end

Many to many relationship with ability to set a state (active)

I have a fully working (for some time now) many-to-many relationship in my Rails application.
Instructors has many Schools (through SchoolsToInstructorsAssociations)
Schools has many Instructors (through SchoolsToInstructorsAssociations)
At this time, I would like the ability to have an "active state" in addition to simply adding or removing an Instructor from a School or a School from an Instructor.
I want an Instructor to be set as inactive before being removed completely at a later point (or reactivated).
My first thought was to add an 'active' boolean to the relationship model (SchoolsToInstructorsAssociations), but there's no simple way to access this attribute to update or query it).
My second thought was to simply create another relationship model with the 'active' attribute, but it's redundant and something extra I have to track.
Maybe a custom many-to-many module? Create a SchoolsToInstructorsAssociations controller?
class Instructor < ActiveRecord::Base
has_many :schools_to_instructors_association
has_many :schools, :through => :schools_to_instructors_association
end
class School < ActiveRecord::Base
has_many :schools_to_instructors_association
has_many :instructors, :through => :schools_to_instructors_association
end
class SchoolsToInstructorsAssociation < ActiveRecord::Base
belongs_to :user
belongs_to :school
end
I also plan to create a history record each time an instructors 'active' state changes or an instructor is removed or added to a school. Not asking how to do this, but wondering if it could be used to track an instructors 'active' state.
class SchoolsController < ApplicationController
def instructors_index
#school = School.find(params[:id])
instructors = find_instructors
#active_instructors = instructors[0]
#inactive_instructors = instructors[1]
respond_to do |format|
format.html # index.html.erb
format.json { render json: #schools }
end
end
private
def find_instructors
active = []; inactive = []
#school.instructors.each do |s|
if SchoolsToInstructorsAssociationRecord.where(user_id: s, school_id: #school)[0].active?
active << s
else
inactive << s
end
return [active, inactive]
end
end
end
class SchoolsToInstructorsAssociationRecord < ActiveRecord::Base
default_scope order('created_at DESC')
attr_accessor :user_id, :school_id, schools_to_instructors_association_id, :active
end
Sounds like you can accomplish what you're trying to do with scopes. Add a boolean column for 'active' as you described for the 'Instructor' class, then you can add scopes for it:
class Instructor < ActiveRecord::Base
...
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
...
end
Then for a given School, you can get the active (or inactive) instructors for that school:
#school.instructors.active
=> SELECT "instructors".* FROM "instructors" WHERE "instructors"."school_id" = <id> AND "instructors"."active" = 't'
If you wanted to do some operations on all the inactive instructors (like destroy them, as an example), you could do:
Instructor.inactive.map(&:destroy)
And you can of course write whatever custom methods you want for the Instructor or School classes.

Rails saving data from associated form

How can I get the data from an associated form and insert it to the associated table from the main model?
class Supplier < ActiveRecord::Base
has_one :account, foreign_key: "acc_sup_id", :autosave => true
self.primary_key = 'sup_id'
end
class Account < ActiveRecord::Base
belongs_to :supplier, foreign_key: "acc_sup_id"
self.primary_key = 'acc_id'
self.table_name = 'accounts'
end
I am having a combined form for Supplier and Account. When I submit I need to find a way to insert the corresponding values to Supplier and Account. The problem is Supplier values is inserting properly but not Account.
I have asked the same question in several forums, groups and even in stack but nobody seems to give a convincing answer.
The basic strategy is to first look at what params are being submitted when the form is submitted. You could add a line in the controller action such as raise params.inspect to see that. Make sure that those paras contain all the data you need; if not then there is some problem in the view that generates that form.
Once you have all the data getting to the controller action, then you need to change the controller action so that is properly interprets all the data and puts it into the correct models.
I cannot give any more specific advice unless you show the code for your view, the result from doing params.inspect, and the code for the controller action that takes the data.
Try this.
Let's assume that there are orders and customers tables and that you want to perform CRUD operations on customers from orders form.
Customer model is very simple
class Customer < ActiveRecord::Base
attr_accessible :name
end
Order model must provide virtual attributes for all customer's attributes (attr_accessor construct). CRUD for customers is provided through callbacks. Validations can be used as well.
class Order < ActiveRecord::Base
attr_accessor :customer_name
attr_accessible :description, :number, :customer_name
belongs_to :customer
validates_presence_of :number
validates_presence_of :description
validates_presence_of :customer_name
before_save :save_customer
after_find :find_customer
after_destroy :destroy_customer
protected
def save_customer
if self.customer
self.customer.name = self.customer_name
else
self.customer = Customer.create(name: self.customer_name)
end
self.customer.save
end
def find_customer
self.customer_name = self.customer.name
end
def destroy_customer
self.customer.destroy
end
end
Example grid for Order model.
class Orders < Netzke::Basepack::Grid
def configure(c)
super
c.model = 'Order'
c.items = [
:description,
:number,
:customer_name
]
c.enable_edit_inline = false
c.enable_add_inline = false
end
def preconfigure_record_window(c)
super
c.form_config.klass = OrderForm
end
end
Example form for Order model.
class OrderForm< Netzke::Basepack::Form
def configure(c)
super
c.model = 'Order'
c.items = [
:description,
:number,
:customer_name
]
end
end

ActiveRecord query all the first items of a unique has-many association

I am having problems to create a Rails ActiveRecord query that retrieves the first Item by unique Activity considering a creation time internal. I also need the values available in ItemStat that is why the includes.
The current method implementation is working, but it is poor and needs optimization.
This is my analogue model:
Activity:
class Activity < ActiveRecord::Base
has_many :items
end
Item:
class Item < ActiveRecord::Base
belongs_to :activity
has_one :item_stat
end
ItemStat:
class ItemStat < ActiveRecord::Base
belongs_to :item
end
Current working method (activities_id are all activities available by an user):
def self.first_items_by_unique_activity(activities_id, time_begin, time_end)
items = Item.includes(:item_stat).where(:activity_id => activities_id, :created_at => time_begin..time_end)
#make the first item unique by activity
uniques = {}
items.each do |item|
identifier = item.activity_id
uniques[identifier] = item if uniques[identifier].nil?
end
uniques.values
end
Thanks any help!