How to change the object view in paper_trail - ruby-on-rails

I have used paper_trail gem for auditing in the application i am developing. I am able to manage most of its features and i was able to display the data in versions table to the user. In doing so the data in object attribute of the versions table is some what unreadable. How can i make it be readable?
Here is my sample output of the object attribute:
version.object retrieves in the following format in a single cell:
--- budget_year: '2014' name: bbb reference_number: j789789 requesting_unit: '798789' quarter: II source_of_fund: Government budget_type: Recurrent procurement_method: Open Bidding procurement_level: National estimated_cost: 4455.0 currency: '4545' purchase_request_id: start_at: 2014-07-30 end_at: 2014-07-31 created_at: 2014-07-24 08:29:38.000000000 Z updated_at: 2014-07-24 08:29:38.000000000 Z id: 1

You could use reify method to see your data like,
> i=Invoice.last.versions.last
=> <PaperTrail::Version id: 158, item_type: "Invoice", item_id: 115, event: "update", whodunnit: "3", object: "---\nid: 115\ncreated_at: 2015-02-05 06:43:17.278448...">
:038 > i.object
=> "---\nid: 115\ncreated_at: 2015-02-05 06:43:17.278448000 Z\nupdated_at: 2015-02-05 06:43:17.278448000 Z\nentity_type: Site\nentity_id: 928\ninvoice_id: WS/14\nuser_id: \nperson_id: \nstatus: 0\nperson_email:\nentity_value:\naddress: ''\nprice: '666'\ndetails: '{\"domain\"=>\"\", \"package\"=>\"23\", \"site_id\"=>\"928\", \"user_id\"=>\"394\", \"years\"=>\"1\"}'\norder_id: '464'\nnorder_type: \nyear: 1\npayment_type: cash\naccount_type: \ncheque_name: ''\ncomment: \ntax: \ncomments: 'Customer made payment by cash with receipt Nos: 041 & 042.'\ncheque_number: \nchequenumber: ''\npayment_level: \ninvoice_type: \n"
> i.reify
=> <Invoice id: 115, created_at: "2015-02-05 06:43:17", updated_at: "2015-02-05 06:43:17", entity_type: "Site", entity_id: 928, invoice_id: "WS/14-15/D-2119", user_id: nil, person_id: nil, status: 0, address: "Near So...", price: "4999", details: "{\"domain\"=>\"\", \"package\"=>\"23\", \"site_id\"=>\"928\", ...", order_id: "464", order_type: nil, year: 1, payment_type: "cash", account_type: nil, cheque_name: "", comment: nil, tax: nil,, cheque_number: nil, chequenumber: "", payment_level: nil, invoice_type: nil>
or
> PaperTrail.serializer.load(i.object)
=> {"id"=>115, "created_at"=>2015-02-05 06:43:17 UTC, "updated_at"=>2015-02-05 06:43:17 UTC, "entity_type"=>"Site", "entity_id"=>928, "invoice_id"=>"W", "user_id"=>nil, "person_id"=>nil, "status"=>0, "person_email"=>"rium#gmail.com", "entity_value"=>"u.com", "address"=>"li ", "price"=>"4999", "details"=>"{}", "orr_id"=>"655", "processed_by"=>"", "order_type"=>nil, "year"=>1, "payment_type"=>"cash", "account_type"=>nil, "cheque_name"=>"", "comment"=>nil, "tax"=>nil, "comments"=>"Customer made payment by cash with receipt Nos: 041 & 042.", "cheque_number"=>nil, "chequenumber"=>"", "payment_level"=>nil, "invoice_type"=>nil}
second way will give the form of hash.

Related

Spree: Return only Orders with Line Items in them

I'm having trouble setting up the controller in a spree app so it only returns orders with line_items in them.
<Spree::Order id: 1057, number: "R498797188", item_total: #<BigDecimal:7f90c2acf4b8,'0.999E1',18(18)>, total: #<BigDecimal:7f90c2acf1e8,'0.1098E1',18(18)>, state: "payment", adjustment_total: #<BigDecimal:7f90c2ace770,'0.0',9(18)>, user_id: nil, completed_at: nil, bill_address_id: 1814, ship_address_id: 1815, payment_total: #<BigDecimal:7f90c2acc358,'0.0',9(18)>, shipping_method_id: nil, shipment_state: nil, payment_state: nil, email: nil, special_instructions: nil, created_at: "2015-09-10 22:31:23", updated_at: "2015-09-10 22:33:03", currency: "USD", last_ip_address: "127.0.0.1", created_by_id: nil, shipment_total: #<BigDecimal:7f90c4b721e8,'0.199E1',18(18)>, additional_tax_total: #<BigDecimal:7f90c4b71fb8,'0.0',9(18)>, promo_total: #<BigDecimal:7f90c4b71e78,'0.0',9(18)>, channel: "spree", included_tax_total: #<BigDecimal:7f90c4b71798,'0.0',9(18)>, item_count: 1, approver_id: nil, approved_at: nil, confirmation_delivered: false, considered_risky: false>
There is a record on Spree::Order called item_count that needs to be > 0, but I don't know what the syntax needs to be in the controller?
#orders = Spree::Order.all.where(:item_count > 0) #this returns the following error: comparison of Symbol with 0 failed
This seems simple, but any help would be greatly appreciated! Thanks!
You can use symbol to check for absolute value, like where(item_count: 0), but not for comparison like that.
Inside where, when you are using symbols, you are actually working on a Hash object.
.where(item_count: 0)= .where({item_count: 0})
and to work with a hash, you should have key-value pair like above, not comparison. {:item_count > 0} is an invalid hash syntax.
For comparison in your case, use string:
#orders = Spree::Order.where('item_count > 0').all
Also, you should use .all, at the end of relation, if all needed. all returns the scope object and is usually meant to fetch all the records matching the query before it.

Rails effective way of looping through daterange

I have ScheduleDay model as;
=> #<ActiveRecord::Relation [#<ScheduleDay id: 1, from: "2017-01-21 00:00:00", to: "2017-01-30 00:00:00", weekday: 100, weekend: 200, weekly: 90, available: true, check_in: "09:00", check_out: "18:00", min_stay: 2, sevendays: false, check_in_day: nil, created_at: "2017-01-14 11:25:18", updated_at: "2017-01-14 11:27:00">, #<ScheduleDay id: 2, from: "2017-02-05 00:00:00", to: "2017-02-15 00:00:00", weekday: 150, weekend: 200, weekly: 140, available: nil, check_in: "09:00", check_out: "18:00", min_stay: 3, sevendays: false, check_in_day: nil, created_at: "2017-01-14 15:53:21", updated_at: "2017-01-14 15:54:43">, #<ScheduleDay id: 3, from: "2017-03-15 00:00:00", to: "2017-06-15 00:00:00", weekday: nil, weekend: nil, weekly: nil, available: false, check_in: nil, check_out: nil, min_stay: 1, sevendays: false, check_in_day: nil, created_at: "2017-01-14 15:56:01", updated_at: "2017-01-14 15:56:57">, #<ScheduleDay id: 4, from: "2017-08-05 00:00:00", to: "2017-09-30 00:00:00", weekday: 500, weekend: 500, weekly: 500, available: true, check_in: "09:00", check_out: "18:00", min_stay: 7, sevendays: true, check_in_day: "Saturday", boat_id: nil, created_at: "2017-01-14 16:01:00", updated_at: "2017-01-14 16:02:10">]>
I have another date range and I would like to loop over my date range in ScheduleDay table and if record is found get some data. If not found then get data as well. I tried couple different way but I m looking for the most efficient way in ruby.
first = Date.parse("05.2.2017")
last = (Date.parse("16.2.2017"))
schedules = ScheduleDay.where(from: Date.today..(last+1.day))
dates = []
(first..last).each do |date|
flag = 0
catch :date_found do
schedules.each do |s|
(s.from.to_date..s.to.to_date).each do |d|
puts date
puts d
if date == d
flag += 1
puts 'found'
throw :date_found
end
end
end
if flag == 0
puts 'date not found'
end
end
end
This is what I have tried so far. But the problem here is I can not access the record if it is not found. If I take;
if flag == 0
puts 'date not found'
end
inside schedules.each... loop then it prints not found for every record in ScheduleDay. I want to loop through all ScheduleDay record and if not found get some data.
EDIT:
I have database records saved by the user. User can customize any date of the year by selecting date range and pricing. I ask user base pricing as well.
So, lets say user entered 15.01.2017 & 21.01.2017 custom price: 100 and base price 200 (base price will be used if date is not found on database date-range).
I would like to return json array of February. So I need;
01.01.2017 -> custom price exists? if not get base price
02.01.2017 -> custom price exists? if not get base price
...
15.01.2017 -> yes! custom price exists get custom price
16.01.2017 -> yes! custom price exists get custom price
17.01.2017 -> yes! custom price exists get custom price
18.01.2017 -> yes! custom price exists get custom price
...
21.01.2017 -> yes! custom price exists get custom price
...
31.01.2017 -> custom price exists? if not get base price
then create json
EDIT2
What if I use;
first = Date.parse("05.2.2017")
last = Date.parse("16.2.2017")
(first..last).each do |date|
schedules.each do |s|
d2 = (s.from.to_date..s.to.to_date)
puts d2 === date
puts d2
puts date
end
end
=== checks date is in the range.

Duplicate found queries on Json data - postgress

am having issues in running queries on data which i have been provided,
if i do Camera.first get the results as
#<Camera id: 6, created_at: "2013-12-12 17:30:32", updated_at: "2015-11-19 10:19:33", exid: "dublin-rememberance-floor2", owner_id: 4, is_public: true, config: {"snapshots"=>{"jpg"=>"/onvif/snapshot"}, "external_http_port"=>8105, "external_host"=>"89.101.225.158", "auth"=>{"basic"=>{"username"=>"admin", "password"=>"mehcam"}}}, name: "My Camera", last_polled_at: "2015-11-27 15:01:51", is_online: false, timezone: nil, last_online_at: "2014-05-01 09:45:39", location: "0101000020E6100000875341A08E0A19C0D6BB896BC6AC4A40", mac_address: nil, model_id: 6, discoverable: false, preview: nil, thumbnail_url: nil>
I am totally unaware about how to get the query run CONFIG object.
example: I want to select all the Cameras list which have same
"external_http_port"=>8105, "external_host"=>"89.101.225.158"
but they are in Config Object.
You can write query like following for json data fetch:
Camere.where("config->> 'external_http_port' = ? and config->> 'external_host' = ?", 8105, '9.101.225.158')

Find out how 'deep' an association is

Please read the following four lines carefully:
first_post = Discourse.create(title: 'I am the first post')
# => #<Discourse id: 56, user_id: nil, title: "I am the first post", body: nil, deleted: nil, delete_date: nil, created_at: "2014-04-07 12:34:53", updated_at: "2014-04-07 12:34:53", forum_id: nil>
first_reply = first_post.replies.create(title: 'I am the first reply to the first post')
# => #<Discourse id: 57, user_id: nil, title: "I am the first reply to the first post", body: nil, deleted: nil, delete_date: nil, created_at: "2014-04-07 12:35:29", updated_at: "2014-04-07 12:35:29", forum_id: nil>
second_reply = first_post.replies.create(title: 'I am the second reply to the first post')
# => #<Discourse id: 58, user_id: nil, title: "I am the second reply to the first post", body: nil, deleted: nil, delete_date: nil, created_at: "2014-04-07 12:35:41", updated_at: "2014-04-07 12:35:41", forum_id: nil>
first_reply_reply = second_reply.retorts.create(title: 'I am the first retort to the second reply to the first retort')
# => #<Discourse id: 59, user_id: nil, title: "I am the first retort to the second reply to the fi...", body: nil, deleted: nil, delete_date: nil, created_at: "2014-04-07 12:36:53", updated_at: "2014-04-07 12:36:53", forum_id: nil>
I regard first_post to have a "depth" of 0 because it isn't a reply to anything.
I regard first_reply to have a "depth" of 1 because it is a reply to first_post (0 + 1 = 1)
I regard second_reply to have a "depth" of 1 because it is a reply to first_post (0 + 1 = 1)
I regard first_reply_reply to have a "depth" of 2 because it is a reply to second_reply that is in-turn a reply to first_post (1 + 1 = 2)
And so on. A reply to first_reply_reply would be 3. (1 + 2 = 3)
To determine the depth of each association I could easily add a column depth to my table and simply create a model method with a before_save hook to iterate the depth, however I wonder if the depth can already be worked out in rails. Maybe an active record method?
You should be able to write:
class Discourse < AR::Base
...
def depth
<parent_association> ? <parent_association>.depth + 1 || 1
end
end
Where <parent_association> is your association to access to record to which this record is a response to. However this will require a number of database calls, so your approach with before_save hook is much better. You can also hava a look at ancestry gem, which very well handles tree-like associations (including depths).

Rails 3: use contents of an array as variables in a where method

I have three models: Isbn, Sale and Channel.
Aim: to get a list in the isbns show.html.erb view which looks something like this:
Isbn: myisbn
Total sales for myisbn: 100
Myisbn sales for channel 1: 50
Myisbn sales for channel 2: 25
Myisbn sales for channel 3: 25
Here are my models.
Isbn.rb model
has_many :sales
has_many :channels, :through => :sales
Sale.rb model (has attributes sales_channel_id, isbn_id, quantity)
has_many :channels
belongs_to :isbn
Channel.rb model:
belongs_to :sale
I've been working in the isbns controller, in the show method, just to get something to work. I thought I'd refactor later - advice on whether any of this stuff should go in the model would be most welcome.
So far I've got this:
#channelisbn = Sale.where("sales_channel_id =?',1).where("isbn_id=?",3)
#channelsalesisbn = 0
#channelisbn.each {|y| #channelsalesisbn =+ y.quantity}
This successfully gets all the sales where Channel ID is 1 and ISBN id is 3. But it's not much use, as the IDs are hard coded. So I got the Channel IDs into an array:
#channellist = Channel.all
#channel = 0
#channelarray = #channellist.map {|z| #channel = z.id}
which gives me a lovely array of [1,2,3,4]
But I can't figure out how to pass the 1, then the 2, then the 3 and then the 4 into a block which can be used to look up an ISBN's sales which have that sales channel id. This is what I tried (still hardcoding the ISBN id - thought I'd tackle one problem at a time), which returned an empty array:
#channelarray.each do |channel|
#channelisbn = []
#channelisbn = Sale.where("sales_channel_id = ?", channel).where("isbn_id = ?",3)
#channelsalesisbn = 0
#result = []
#result << #channelisbn.each {|a| #channelsalesisbn =+ a.quantity}
end
I was then going to sum the contents of the array.
Any help would be gratefully received. This is my first post, so my zero acceptance rate will change soon!
UPDATE
Just to finish this question off, here's where I've ended up, which is great, and ready for tinkering with: an array, nicely grouped, giving me sales by isbn by channel. Thanks for the group_by tip off!
#in the show action in the isbns controller:
#isbn = Isbn.find(params[:id])
#channelarray = Channel.select(:id).all
#channelarray.group_by {|i| Sale.where("channel_id = ?",i).where("isbn_id =?", #isbn)}
From the console, line breaks added for clarity:
(sneakily set #isbn = 3 first of all, since in the console you can't pass params from a view, so the #isbn instance defined in the controller is nil in the console)
ruby-1.9.2-p180 :067 > #channelarray.group_by {|i| Sale.where("channel_id = ?",i).where("isbn_id =?", #isbn)}
=> {[#<Sale id: 1, isbn_id: 3, quantity: 10000, value: 12000, currency: "GBP", total_quantity: nil, created_at: "2011-05-06 12:30:35", updated_at: "2011-05-07 17:43:13", customer: "Waterstone's", retail_price: nil, discount: nil, invoice_date: "2011-05-24">, #<Sale id: 2, isbn_id: 3, quantity: 1000, value: 500, currency: "GBP", total_quantity: nil, created_at: "2011-05-07 09:37:53", updated_at: "2011-05-07 19:14:52", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-02-05">]=>[#<Channel id: 1>],
[#<Sale id: 3, isbn_id: 3, quantity: 500, value: 1500, currency: "", total_quantity: nil, created_at: "2011-05-07 09:38:11", updated_at: "2011-05-07 19:15:07", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-12-05">, #<Sale id: 4, isbn_id: 3, quantity: 45, value: 300, currency: "", total_quantity: nil, created_at: "2011-05-07 09:38:38", updated_at: "2011-05-07 19:15:36", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-06-05">]=>[#<Channel id: 2>],
[]=>[#<Channel id: 3>],
[]=>[#<Channel id: 4>]}
UPDATE 2
Ha, the hash I generated had the key value pairs the wrong way round. The array containing the sales data was the key - it should have been the value. Rubydocs saved the day:
#salesbychannel = #salesbychannelwrong.invert
The invert method switches the key-value pairs. Sweet.
What you're looking for is passing an array to a ARel#where(), like this:
Sale.where(:sales_channel_id => #channelarray)
This should execute an IN query. If that's not working, you can always pass the array to ActiveRecord#find, like this:
Sale.find(#channelarray)
Hope this helps

Resources