Let's say I have a table for a model Score, and a table for a model Multiplier. Both of these models have attributes date and value. I want to now create a new object of a different model Total, that corresponds to the date for Score and Multiplier. Here's the idea, though I don't think it's a good solution:
def create
#scores = Score.all
#scores.each do |score|
Total.create(:date => score.date, :value => score.value + Multiplier.find_by_date(score.date).value)
end
end
Essentially, how can I add the values of two fields from separate models to create a third object of a different model, in an elegant way? Thanks in advance!
Related
I want to know if there is an elegant way to merge multiple records from different Models into one new object ?
The case is to build a 'stream' or 'feed' of the app content, like in Facebook.
In detail, each record have multiple and different columns. This is the Models and columns :
Product [name, price]
Post [tagline, image]
Member [name, username, profilepic]
Selection [name, tagline]
The code I tried :
#new_object = #product = Product.find(n) + #post = Product.find(n) + #member = Member.find(n) + #selection = Selection.find(n)
But this is not working because of the differences of fields. I think we have to map into a Hash ?
This is how I will use the final object :
#new_object.each do |stream|
stream.foo
stream.bar
end
So, the goal : take each record and display the content with .each
Luxury : have the oportunity to sort randomly the results.
Many thanks!
You can create a PORO (plain old ruby object) to represent the combined object so something like:
class Stream
attr_accessor :product, :post, :member, :selection
def initialize(attrs)
assign_attributes(attrs)
end
end
Then just initialize and create as many stream objects as you need using Stream.new(attrs). You can create an array of stream objects and loop through them to render or show multiple stream data.
For sorting an array of objects by its attributes you can use
objects.sort_by {|obj| obj.attribute}
I'm looking at using the new Rails 5 attributes API for a custom data type, ideally storing the data in two database columns, one for the data value and one for some extra type information.
The Attributes API seems to be designed to work with just one database column and I'm wondering if I'm missing a way to use two columns.
Example
Imagine a Money object, with one decimal or integer column for value and one string column for currency code. I'd pass in my custom money object, store it two columns, and then reading it back would combine the two columns into a Money object.
I've considered serializing the value and currency into a single Postgres JSON column, but I want to be able to do fast SQL SUM queries and sorting on just the value columns, so this doesn't seem ideal.
Thanks in advance for any insight.
I guess you're thinking about creating a ValueObject within your model.
There is ActiveRecord::Aggregations for that. Example:
class Customer < ActiveRecord::Base
composed_of :balance, class_name: "Money", mapping: %w(balance amount)
end
class Money
include Comparable
attr_reader :amount, :currency
EXCHANGE_RATES = { "USD_TO_DKK" => 6 }
def initialize(amount, currency = "USD")
#amount, #currency = amount, currency
end
def exchange_to(other_currency)
exchanged_amount = (amount * EXCHANGE_RATES["#{currency}_TO_#{other_currency}"]).floor
Money.new(exchanged_amount, other_currency)
end
def ==(other_money)
amount == other_money.amount && currency == other_money.currency
end
def <=>(other_money)
if currency == other_money.currency
amount <=> other_money.amount
else
amount <=> other_money.exchange_to(currency).amount
end
end
end
Can't answer your question directly unfortunately, but your example got me thinking. the money-rails gem allows use of a separate currency column. Perhaps it would be worth it to dig thru that gem to see what they are doing behind the scenes.
I have a requirement where I need to calculate the average of units sold for a product based on the company they were sold at.
The scenario is we're importing data from a legacy database, and when importing I'd like to perform some calculations based on the difference between units sold for new item and the average of the existing item's, when they were sold at the same company.
The model is called Product and has attributes of:
name
interest (How many units were sold)
company (What company they
were sold at)
Now previously, I am able to calculate the average of each company on the model like so:
def self.average_interest(company)
where(company: company).average(:interest)
end
But now I am trying to do the calculation on a rake task.
Here's what I came up with and it's not working:
#company = u.Company
#u.Company is the field name from the legacy database
def average_interest
Product.average(:interest, :conditions => ['company = ?', #company])
end
Any ideas?
Thanks!
EDIT:
Have updated it from '#company' to #company however the value being returned is still incorrect
In your rake task you can pass in the variable, so something like this:
def average_interest(company)
Product.average(:interest, :conditions => ['company = ?', company])
end
unentered_legacy_companies.each do |u|
average_interest(u)
end
after playing around, looks like it was only a slight adjustment from the original code that was needed.
Just had to add the model (Product) to the query in the code:
def average_interest(company)
Product.where(company: company).average(:interest)
end
And then I am storing it in a variable like so:
#company_average = average_interest(u.Company)
I have a User model with a name attribute. In my PagesController, I want to set an instance variable equal to all of the User objects, but I want to order them based on last name. I know I can do:
#sortedusers = User.order(:name => :asc)
to order the users based on their name attribute, but how do I do it based on last name? (i.e. how do I order the Users based on the last word of their name attributes?
Thanks.
Define a virtual attribute last name in your model
def last_name
name.split(' ').last
end
and then
User.order(:last_name => :asc)
I'd suggest storing the users' last name separately. Barring that, you can use sort_by, like so:
items.sort_by! { |a| a.split(' ') } or something along those lines. Note, this most likely cannot be used straight, it's merely intended to point you in the right direction, as most of my answers are.
In my tabel I have:
rating_score => The current score
ratings => The number of ratings which led to the score
I want to create a "fake" column named rating which is (rating_score/ratings) in model. That I can use in my controller to order after and in my view.
How should I create this in my model?
Notice that you cannot have the SQL query order your results by a virtual attribute.
What you can do is just define the method like this in your model:
def rating
rating_scope / ratings
end
and order your resultset in ruby based on the value:
results.sort_by(&:rating)