Ruby Ohm, how to find a record in a set or collection? - ruby

This question is related to other: Many-to-many relationships with Ruby, Redis, and Ohm
I have a Model with a collection and I would like to look for an id. How can I do this?
Models
class User < Ohm::Model
attribute :name
end
class Event < Ohm::Model
attribute :title
collection :attendees, :User
end
Usage
#fran = User.create(name: "Fran")
#event = Event.create(title: "Party in Las Vegas")
#event.attendees.add(#fran)
Event.find(attendees: #fran)
=> Ohm::IndexNotFound exception!
What I would like is to be able to ask by the Users which attending of a Event and what are the Events by an User.

You want a set of all users attending an event, and you also want a set of all events attended by a user. The simplest way would be to create a model Attendee that references both a user and an event:
class Attendee < Ohm::Model
reference :user, :User
reference :event, :Event
end
u = User.create(name: "foo")
e = Event.create(name: "bar")
a = Attendee.create(user: u, event: e)
Attendee.find(user_id: u.id).include?(a) #=> true
Attendee.find(event_id: e.id).include?(a) #=> true
Then if you want all users that attended an event:
Attendee.find(event_id: e.id).map(&:user)
Or all the events attended by a user:
Attendee.find(user_id: e.id).map(&:event)
You can create methods in User and Event as shortcuts for those finders:
class User < Ohm::Model
attribute :name
def events
Attendee.find(user_id: id).map(&:event)
end
end
class Event < Ohm::Model
attribute :name
def visitors
Attendee.find(event_id: id).map(&:user)
end
end
Then:
u.events.include?(e) #=> true
e.visitors.include?(u) #=> true
Let me know if it works for your use case.

I'm not familiar with Ohm but I think you only need to add the index
class Event < Ohm::Model
attribute :title
collection :attendees, :User
index :attendees
end
Then you should be able to do
Event.find(attendees: #fran)
OR
Event.find(attendees: #fran.id)

Related

Association Issue

I have 3 models User, Club and Mcq.
In club model. I assign club (class) as -
9-physics
9-chemistry
10-physics
10-chemistry...
Here is my Association
class User < ActiveRecord::Base
has_and_belongs_to_many :clubs
end
class Club < ActiveRecord::Base
has_many :mcqs
has_and_belongs_to_many :users
end
class Mcq < ActiveRecord::Base
belongs_to :club
end
In my student view (student show index) I show all club (as subject) and after click on a subject I just want to show Mcq topic of that related subject.
for that my Club Controller is -
class ClubsController < ApplicationController
#its show subject list
def student_show_index
#club = current_user.clubs
end
#its show topic according to subject.
def student_show_topic
#club = current_user.clubs
#mcq = #club.first.mcqs.order('created_at DESC')
end
end
So my question is, when I click on subject physics it show all the Mcq of 9th. and same for chemistry.
I just want to filtered Mcq according to subject.
You have to send a params as club_id in the link of subject which you are clicking. eg. <%=link_to "Subject", x_path(club_id: n) %> Then you can catch this params in your controller action as params[:club_id]. then rewrite the controller action as following
def student_show_topic
#club = Club.find(params[:club_id])
#mcq = #club.mcqs.order('created_at DESC')
end
Not you may need to permit club_id this params in your controller, if not yet added. Hope this will help you. Let me know if any issues?

How to retrieve object with relationship stored in string variable in rails 3.2.12 at run time?

Let's say there are models customer, account and address:
class Customer
has_many :accounts
end
class Account
belongs_to :customer
has_many :addresses
end
class Address
belongs_to :account
end
Given an object address, its customer could be retrieved as:
customer = address.account.customer
Now let's store the relationship in a string variable address_relation = 'account.customer'. Given an address object, is there a way to retrieve its customer with the string variable address_relation like:
customer = address.address_relation ?
thanks for the help.
I'd do something like
customer = address.address_relation.split(".").inject(address) do |object, method|
object.send(method)
end
You could switch send by try if there's a chance there is a nil object in your relation chain
Not sure I understand the problem correctly, but I guess you can use Ruby's send method to dynamically resolve the model relations.
object = customer
methods = "account.customer".split(".")
methods.each do |m|
object = object.send(m)
end

Rails callback after_save not setting attribute

I'm dealing with a problem on a after_save callback. I'm sure there is a easy solution, but I can't figure it out.
I have 3 models: User, Product, Bid. The Product table contains a boolean field "available", which is set default to true. If a User places a bid, the available field should be set to false.
I thought this should work with a callback on the bid model.
I can access and set the available field in the console by typing:
b = Bid.last
b.product.available = false
=> false
However I can't change it via the controller, so I think it doesn't execute the callback. What am I doing wrong?
Thank you all for your help!
product.rb
class Product < ActiveRecord::Base
has_one :bid
belongs_to :user
end
bid.rb
class Bid < ActiveRecord::Base
attr_accessible :product_id, :user_id, :product
belongs_to :product
belongs_to :user
after_save :set_product_status
def set_product_status
self.product.available = false
end
end
bids_controller.rb
...
def create
#user = current_user
product = Product.find(params[:product_id])
#bid = #user.bids.build(product: product)
respond_to do |format|
if #bid.save
...
Since bid belongs_to product, you should save the product too.
def set_product_status
self.product.available = false
self.product.save
end

Rails 3. Decide on save if the object should be saved or not

iam just asking myself, whats the best solution for my problem.
Here are my models:
class Product < ActiveRecord::Base
has_many :prices, :class_name => "ProductPrice"
accepts_nested_attributes_for :prices
end
class ProductPrice < ActiveRecord::Base
belongs_to :product
end
The controller
def create
#product = Product.new(params[:product])
#product.save
...
end
What i want to do is to prevent all ProductPrices from being saved when product_price.value == nil or product_price.value == 0.0
before_save hook in ProductPrice. return false will rollback the whole transaction, thats not what i want to do. i just want to "kick" all prices with value == 0 or value == nil
first kick all price_params from params[...] and than call Product.new(params[:product]) seems not to be the rails way eighter...
after Product.new(params[:product]) iterate over all prices and delete them from the array. but the logic should be in my models right? i just dont want to repeat myself on every controller that creates new prices...
can someone tell me the best solution for that? whats the rails way?
thanks!
What you want it called a validation hook, something like this:
class ProductPrice < ActiveRecord::Base
belongs_to :product
validates :value, :numericality => {:greater_than => 0.0 }
end
See http://guides.rubyonrails.org/active_record_validations_callbacks.html for other ways you may want to do this with finer control.
To avoid adding these invalid prices in the first place, you can remove them from the nested attributes hash like this:
class Product < ActiveRecord::Base
def self.clean_attributes!(product_params)
product_prices = product_params['prices'] || []
product_prices.reject!{|price| price['value'].to_f == 0 rescue true }
end
end
Product.clean_attributes!(params[:product])
Product.new(params[:product])

ActiveRecord :through to set default values on through table

I would like to set a default value in a has_many through association.
Lets say I have three models:
People
Friends
Dogs
A person can request that a dog becomes their friend.
So a person would create an association where friends has an active column = false.
User
has_many :friends
has_many :dogs, :through => :friends
Now when I assign a dog to a user
User.find(1).dogs << dog
The friends table has null in the active column.
My friends model is defined as
Friend
def initialize(args = {})
super(args)
active = false
end
yet this does not work because the friend object is never created. Do I have to manually create one?
To set default values of a model; In the model I do this
before_save :default_values
private
def default_values
self.status = :active unless self.status
end
Not sure if this is the correct approach though.
With the following code you'll create a new friend with active = false
class User < ActiveRecord::Base
has_many :friends, :conditions => "active = false"
has_many :dogs, :through => :friends
end
#user = User.new
#user.friends.create #or #user.friends.build

Resources