has_many relationship with two foreign keys - ruby-on-rails-4

I have a relationship in which I'm trying to reference two different foreign keys. Excuse the lame example here, but I'd like to do something like the following:
class Account
has_many :orders,
-> { where('orders.account_id IS NULL OR orders.account_id = ?', self.id ) },
primary_key: :user_id, foreign_key: :user_id
end
However the dynamic value in the where clause is not correct, throwing a 'NoMethodError: undefined method `id' for ActiveRecord_Relation'.
Any ideas on how to reference the parent record within the where clause?

You don't have a record to call .id on. I guess that this is what you are looking for:
class Account
has_many :orders,
-> { where('orders.account_id IS NULL OR orders.account_id = accounts.id') },
primary_key: :user_id, foreign_key: :user_id
end

I believe I just came across the answer. By providing a property to the lambda, rails will provide the record.
class Account
has_many :orders,
->(record) { where('orders.account_id IS NULL OR orders.account_id = ?', record.id ) },
primary_key: :user_id, foreign_key: :user_id
end

Related

UnknownAttributeError for nested form

I have two model as:
Customer:
has_many :products, :dependent => :destroy
accepts_nested_attributes_for :products, reject_if: proc { |attributes| attributes['product_id'].blank? }
Product:
belongs_to :customer
products controller:
def product_params
params.require(:product).permit(:name, :first_build)
end
customers controller:
def customer_params
params.require(:customer).permit(:first_build, :name, :product_id,
products_attributes: [:first_build, :customer_id])
end
So in the customers controller I do this
#customer.products.build(:first_build => true)
but I get this error
unknown attribute 'first_build' for Prodcut
but when I do this #customer.products.build(:name => "test product name")
it works perfectly without any error. One thing to note here, first_build is not a column in the products table.
If you want to pass attributes that are not in the table, you can create a "temporary" attribute which will not be stored in the table but will be available while the object is in memory.
class Product < ActiveRecord::Base
attr_accessor :first_build
...
end

Rails - use collection_select in a simple_form for a has_many_through association

I need help with a create form for a has_many_through association which also specifies a class name:
class Sponsor < ActiveRecord::Base
has_many :member_contacts
has_many :contacts, through: member_contacts, class_name: :member
accepts_nested_attributes_for :address, :contacts
end
class Contact < ActiveRecord::Base
has_many :member_contacts
has_many :sponsors, through: member_contacts
end
class MemberContact < ActiveRecord::Base
belongs_to :contact
belongs_to :sponsor
end
sponsors_controller.rb
def create
#sponsor = Sponsor.create(sponsor_params)
#sponsor.contacts.build
end
def sponsor_params
params.require(:sponsor).permit(:name,:website,:email,
:contact_first_name, :contact_surname, contacts_attributes: [], address_attributes: [:flat, :street, :postal_code, :city])
end
sponsor/_form.html.haml
= simple_form_for #sponsor do |f|
= f.association :contacts, collection: Member.all, label_method: :full_name
This is failing with the error 'unpermitted params, contact_ids', because
"contact_ids"=>["", "4", "5", "6"]
is being passed in the params hash. In the form I'd like a drop down list of all the members and the ability to select multiple members which will be saved against the sponsor as contacts.
How do I set up the contacts_attributes in sponsor_params in the controller and the collection_select simple_form helper in the view?
To get the form working, I added a foreign key to the sponsor class
has_many :contacts, through: member_contacts, class_name: 'Member', foreign_key 'member_id'
changed the strong params in the controller
def sponsor_params
params.require(:sponsor).permit(:name,:website,:email, contact_first_name, :contact_surname, contact_ids: [], address_attributes: [:flat, :street, :postal_code, :city])
end
and removed the association in the view, using collection_select
= f.collection_select :contact_ids, Member.all, :id, :full_name,
{ selected: #sponsor.contacts.map(&:id) }, { multiple: true }
You can set like this:
params.require(:sponsor).permit(:name,:website,:email, contact_ids: []...)
Note that permit(:contact_ids) will fail, but permit(contact_ids: []) works.

Active Record join, SUM and group_by on votes given

I'm using rails 4.2 and ruby 2.2
I have the following three models
Entrant (Devise User)
Entrant.column_names
=> ["id", "email", "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at", "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "created_at", "updated_at", "confirmation_token", "confirmed_at", "confirmation_sent_at", "unconfirmed_email", "entrant_name"]
class Entrant < ActiveRecord::Base
has_many :entries
has_many :votes, :through => :entries
end
Entry
Entry.column_names
=> ["id", "entrant_id", "title_of_work", "price", "created_at", "updated_at", "media_file_name", "media_content_type", "media_file_size", "media_updated_at", "paid", "height", "width", "type_of_media"]
class Entry < ActiveRecord::Base
belongs_to :entrant
has_many :votes
has_many :entrants, :through => :votes
end
Vote
Vote.column_names
=> ["id", "entry_id", "judge_id", "score", "created_at", "updated_at"]
class Vote < ActiveRecord::Base
belongs_to :entry
belongs_to :judge
end
I need a query that will return the following table. I've tried starting with Entrant and joining Votes but nothing has worked.
The query needs to pull out all entries, and sum the votes.score field and order by votes.score but it also needs to group by entry so that the entries are not duplicated.
This is as close as I have got, but it doesnt work.
#entries = Entrant.joins(:entries).joins(:votes).select('entrants.*, entries.*, SUM(votes.score) as total_votes').distinct.group('entrants.id, entries.id, votes.score')
It should be something like:
Entry.joins(:entrant).joins(:votes)
.group('entries.id')
.order('SUM("votes.score")').
.pluck(:entrant_name, :title_of_work, 'SUM("votes.score")'),'COUNT("votes.score")')
I worked this out in the console with a similar set of relationships I have set up so it may need a bit of tweaking but it should get you pointed in the right direction. Let me know if you get stuck.

Rails 4 has_one through with where clause

I am trying to establish a direct relation via has_one between two models, Client and Address as in has_one :billing_address but Client doesn't have a direct relation to Address, Contact does, the models:
Client
class Client < ActiveRecord::Base
belongs_to :contact
accepts_nested_attributes_for :contact
end
Contact
class Contact < ActiveRecord::Base
has_one :client
has_many :addresses, dependent: :destroy
accepts_nested_attributes_for :addresses, allow_destroy: true
end
Address
class Address < ActiveRecord::Base
belongs_to :contact
enum kind: [:address, :shipping, :billing]
end
So what I want is to to be able to do Client.shipping_address or Client.billing_address, the enum in the Address model is what will allow the query. The reason behind that is because the Contact of Client will have two address records, one for billing and one for shipping and I want quick access via relations
I tried in the Client model:
has_one(:billing_address, -> { where(kind: :billing) }, class_name: Address, through: :contact)
But when in the view I o:
client.billing_address
I get a undefined method to_sym' for nil:NilClass And I can't seem to resolve it, thanks.
You need to specify the :source on the association since it cannot be inferred.
has_one :billing_address, through :contact, source: :addresses, -> { where(kind: :billing) }
Without :source, it's going to look for a :billing_address association on the Contact model.
Source
Update
After reading up on the enum docs, it looks like you may need to modify the scope, referencing the mapping directly:
-> { where(kind: Address.kinds[:billing]) }
I believe this is because the :kind field in the database is expected to be type INTEGER.

Mongoid belongs_to specify foreign_key

I'd like to set up a relationship between two Mongoid models with has_many and belongs_to and specify a foreign key, like so:
class Author
include Mongoid::Document
field :serial_num, :type => Integer
field :author_name, :type => String
has_many :books
end
class Book
include Mongoid::Document
field :serial_num, :type => Integer
field :book_name, :type => String
belongs_to :author, foreign_key: 'serial_num'
end
This doesn't work, however. My IRB output:
irb :001> b = Book.first
=> #<Book _id: 1, serial_num: "12345", book_name: 'something', author_id: nil>
irb :002> b.author
=> nil
Is it possible to specify 'serial_num' as a foreign key for this relationship, or am I stuck with author_id?
Many thanks.
You need to set both foreign_key and primary_key given your field definitions. The code you gave does respect primary_key but on author this value is looked up in _id, not serial_num. See the documentation for further details and examples.
belongs_to :author, foreign_key: 'serial_num', primary_key: 'serial_num'
I know this is an old post, but I'm guessing it has to do with the field type the foreign key is stored as. If it's not a BSON ObjectId, then it may not return anything.