Mongoid fields auto sum - ruby-on-rails

Everyone! I have a model:
class Model
include Mongoid::Document
field :price1, :type =>Integer
field :price2, :type =>Integer
field :price3, :type =>Integer <== I want this field to be always result of price1 + price2
end
My question is: How can I make :price3 to be always autofilled by sum of price1 + price2.
Thank you very much for help!

You want to use the callbacks interface. There are various callbacks exposed such as:
require "mongoid"
require "pp"
Mongoid.configure.connect_to("test")
class Model
include Mongoid::Document
field :price1, type: Integer
field :price2, type: Integer
field :price3, type: Integer
store_in collection: "mymodel"
before_save do |document|
document.price3 = document.price1 + document.price2
end
end
model = Model.new
model.price1 = 2
model.price2 = 3
model.save
Which results in the "price3" field being set to the sum of the other two values.

Related

Rails: Creating a Search Filter Based on Dropdowns for Mongoid Database

On my index page I have a few dropdowns that the user can select as a filter for searching a Mongo collection. These dropdowns correspond to fields set in my model. There is also an open text input field they can use to search the text fields "scenario name" and "scenario body" in the collection. I can't seem to find much of any documentation on how to chain Mongoid queries to narrow down search results.
The index.erb view page has a form_tag with various selectors for the fields I want the user to search on, and a text input for the scenario name and body fields.
Here is my Index Controller:
def index
#scenarios = if params[:search]
Scenario.search(params)
else
Scenario.all
end
end
And my "scenarios" model:
class Scenario
include Mongoid::Document
field :submitter, type: String
field :scenario_name, type: String
field :scenario_body, type: String
field :creation_date, type: Date
field :modified_date, type: Date
field :test_type, type: String
field :application, type: String
field :pillar, type: String
def self.search(search)
self.or({submitter: /.*#{search[:submitter]}.*/i},
{scenario_name: /.*#{search[:search]}.*/i},
{scenario_body: /.*#{search[:search]}.*/i},
{creation_date: search[:creation_date]},
{modified_date: search[:modified_date]},
{test_type: /.*#{search[:test_type]}.*/i},
{application: /.*#{search[:application]}.*/i},
{pillar: /.*#{search[:pillar]}.*/i})
end
end
How should I go about creating a method or query that can filter on one, many, all of the dropdown options and an open text search?
This is how I went about it. Does not seem very rails-like at all though, but it works.
In Scenario model:
def self.search(search)
search_array = [{scenario_name: (/.*#{search[:search]}.*/i if search[:search].present?)},
{scenario_body: (/.*#{search[:search]}.*/i if search[:search].present?)}]
search_array.map {|a| a.reject! {|k, v| v.nil?}}
search_array.delete_if {|hash| hash.empty?}
select_array = [{submitter: (search[:submitter] if search[:submitter].present?)},
{test_type: (search[:test_type] if search[:test_type].present?)},
{application: (search[:application] if search[:application].present?)},
{pillar: (search[:pillar] if search[:pillar].present?)}]
select_array.map {|a| a.reject! {|k, v| v.nil?}}
select_array.delete_if {|hash| hash.empty?}
mongo_query = ['$and' => (select_array if select_array.present?), '$or' => (search_array if search_array.present?)]
mongo_query.map {|a| a.reject! {|k, v| v.nil?}}
mongo_query.delete_if {|hash| hash.empty?}
where(mongo_query[0]).to_a
end

How to update one attribute in mongoid

How to update only :share_count, maybe this should be done with upsert ?
I use ruby on rails and mongoid
class FeedEntry
include Mongoid::Document
require 'social_shares'
field :name, type: String
field :url, type: String
field :share_count, type: Integer
before_save :load_shares
def load_shares
self.share_count = SocialShares.total url, %w(sharedcount)
end
def self.update_shares_today
#feed_entries = FeedEntry.today.all
#feed_entries.each do |feed_entry|
feed_entry.update
end
end
end
count = SocialShares.total url, %w(sharedcount)
update_attributes share_count: count

Mongoid Rails - Is there a way to check the field's datatype before saving?

I have this class ProfitLoss which consists of these fields. I want to call this method zero_if_blank on before_validation as before_save is not working and what i want to do is assign 0 to those values which are blank and are of Integer when coming from the form. I searched a lot like the Mysql columns_hash but didn't find any method to give the type of each field in mongo.
class ProfitLoss < Generic
include Mongoid::Document
include Mongoid::Timestamps
include MongoMysqlRelations
field :fiscal_year, type: String
field :sales_excluding_other_incomes, type: Integer
field :other_incomes, type: Integer
field :closing_stock, type: Integer
before_validation :zero_if_blank
def zero_if_blank
pp self.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
end
end
this piece of code did the work :)
def zero_if_blank
self.fields.each do |k,v|
if v.type == Integer && self.attributes[k] == nil
self.__send__("#{k}=", 0)
end
end
end

Create or increment a field in Mongoid with Rails 4

I have a model like this:
class Invoice
include Mongoid::Document
field :local, type: String
field :date, type: DateTime
field :total, type: Float
end
class LogInvoice
include Mongoid::Document
field :date, type: Date
field :local, type: String
field :summary, type: Hash
end
The field summary is a Hash like this:
summary = {invoices : 0, amount : 0.0}
For each invoice stored, I must create an LogInvoice for that day with total number of Invoice (count of Invoice) in LogInvoice.summary[:invoices] and with the total ammount of money (summatory of Invoice.total) in LogInvoice.summary[:amount]
If the Invoice exist I must to update the LogInvoice of that day.
I can't know if a object existe because LogInvoice.find() returns an exception if it doesn't, so how can I update an existing object LogInvoice or created if it doesn't?
Thank you
If I've understood your question you should do something like this:
my_invoice_criteria = Invoice.all # or Invoice.where date: the_date_I_want or anything else
my_invoice_criteria.each do |invoice|
log_invoice = LogInvoice.find_or_create_by date: invoice.obtain_proper_date
#Use this for atomic persistence
log_invoice.inc :"summary.invoices" => 1
log_invoice.inc :"summary.amount" => invoice.total
#Use this for standard persistence
log_invoice.summary[:invoices]+=1
log_invoice.summary[:amount]+=invoice.total
log_invoice.save
end
Ref:
Atomic persistence Docs
Standard persistence Docs

overriding attribute function rails mongoid

I have a model like this.
class Money
include Mongoid::Document
#interval is how often the compensation is paid
field :salary, :type => Integer # must be saved in cents
field :commission, :type => Integer # must be saved in cents
field :total, :type => Integer # must be saved in cents
end
total is sum of salary and commission. salary and commission both are saved in cents.
But my problem is that when it is edited i need to show it in dollar figure.
For example, if salary in cent is 5000000 then when i press edit i need to see 50000 in the salary textbox.
Some other solutions are also welcomed
If you want to enforce this pattern at the model level then you could override the setters and getters:
class Money
#...
def salary
self.salary / 100
end
def salary=(value)
self.salary * 100
end
end
In this case you'll have the editing/displaying for free, without writing any helpers.
Although, I think the proper way for doing it is at the view level through a helper definition. The model should not be concerned with this.
Look at ActionView::Helpers::NumberHelper. In your case you could write your own helper like this:
def money_to_textbox (money)
money / 100
end
This helper method should be placed in app\helpers and then in a view you can use like this:
<%= money_to_textbox #money %>

Resources