Is there a way to set time to live for a document and then it gets destroyed. I want to create guest users that are temporary per session, so after a week the document gets removed automatically.
MongoDB (version 2.2 and up) actually has a special index type that allows you to specify a TTL on a document (see http://docs.mongodb.org/manual/tutorial/expire-data/). The database removes expired documents for you--no need for cron jobs or anything.
Mongoid supports this feature as follows:
index({created_at: 1}, {expire_after_seconds: 1.week})
The created_at field must hold date/time information. Include Mongoid::Timestamps in your model to get that for free.
UPDATE:
If you want to expire only a subset of documents, then you can create a special date/time field that is only populated for that subset. Documents with no value or a non-date/time value in the indexed field will never expire. For example:
# Special date/time field to base expirations on.
field :expirable_created_at, type: Time
# TTL index on the above field.
index({expirable_created_at: 1}, {expire_after_seconds: 1.week})
# Callback to set `expirable_created_at` only for guest roles.
before_create :set_expire, if: "role == :guest"
def set_expire
self.expirable_created_at = Time.now
return true
end
First you should add include Mongoid::Timestamps to your model.
Second you should add a cron job or a worker of some sort that will run (if you don't want perhaps you can use this gem https://github.com/daddye/foreverb)
And then you can easily set up a check for the gem to see
if model.created_at > 1.week.ago
model.destroy
end
Related
I've to make posts inactive after a given date and time by the user who creates these posts. I've added a boolean field "published" to make a post active or unactive.
If the post is active, every visitor will see the post. If it's inactive, the post will be seen in the user dashboard as inactive.
For you guys what is the best way to make a post inactive after the given datetime passed? That should be automatic but I don't think the suitable way is using Active Job and ;
Check all posts in the db if active,
If active, compare the given datetime and current datetime
If needed, make it inactive
I'm using heroku, so that'll make my worker busy all the time.
If you simply plan to fetch and display posts, rather than setting the boolean value, you could just add a scope to the model:
scope :published, -> { where('publish_at < ?', Time.now) }
And use like this Post.published
Let me know if this helps.
Update 1:
If you need to determine if a post is active or not, add a method to the model like this,
def active?
self.publish_at < Time.now
end
You can do some things:
Option 1:
Based in the #jawad-khawaja answer, I think a better approach is to use expired_at instead of published_at because for me, a publish date is a date when a post is available for people. This way the user can define an expiration date for his own post (not the same publish date).
Here some example how to you can get active/inactive posts based on its expiration date
# active posts
scope :published, -> { where('expired_at > ?', Time.now) }
# inactive posts
scope :unpublished, -> { where('expired_at < ?', Time.now) }
Option 2:
If you have an attribute published as boolean and you really need mark it automatically, the option is to use whenever gem
CONS for this option:
You will have two attributes representing the same thing: published as boolean and expiration_datetime as datetime
If the minimum unit for an expiration date is a minute, you need to check every minute if every not-expired post enter to the expired state. And you will have probably an overload for your server.
Conclusion:
My recommended way is to choose the option 1.
In our Rails app, the user (or we on his behalf) load some data or even insert it manually using a crud.
After this step the user must validate all the configuration (the data) and "accept and agree" that it's all correct.
On a given day, the application will execute some tasks according the configuration.
Today, we already have a "freeze" flag, where we can prevent changes in the data, so the user cannot mess the things up...
But we also would like to do something like hash the data and say something like "your config is frozen and the hash is 34FE00...".
This would give the user a certain that the system is running with the configuration he approved.
How can we do that? There are 7 or 8 tables. The total of records created would be around 2k or 3k.
How to hash the data to detect changes after the approval? How would you do that?
I'm thinking about doing a find_by_user in each table, loop all records and use some fields (or all) to build a string and hash it at the end of the current loop.
After loop all tables, I would have 8 hash strings and would concatenate and hash them in a final hash.
How does it looks like? Any ideas?
Here's a possible implementation. Just define object as an Array of all the stuff you'd like to hash :
require 'digest/md5'
def validation_hash(object, len = 16)
Digest::MD5.hexdigest(object.to_json)[0,len]
end
puts validation_hash([Actor.first,Movie.first(5)])
# => 94eba93c0a8e92f8
# After changing a single character in the first Actors's biography :
# => 35f342d915d6be4e
I have a form that is used to generate a report. In this form I have a number of flags set - that will then dictate what my report does.
These variables are then passed to the model and I pick them up
attr_accessor :make_charge
At this point I know I have the variable as I can log it.
I then pass off to the generatereport file.
This file picks up
attr_accessor :member
attr_reader :make_charge
The report is generated - and the various properties the member has are ok, but I cannot access the value of make charge.
How how do I set a value in one file and then access in another? It would seem to me the attr_accessor and attr_reader do this - but I seem to be doing it wrong. (Which we have all agreed on)
The report is generated just fine - what I want to do is a new action on the records of this report - based on a setting in the original form submission. I was hoping to do it in one process - to set the parameters - have the report run and then the records adjusted. The flag is not part of the model. it's a flag if set do something once report is complete.
The report generator is
MemberAccountsByStatusAndDateReportGenerator.new(
Member.
includes(:balances).
joins(:balances).
where{with_balances}.
where(status: report_options[:status]).
where{last_login_at >= start_date }.
where{last_login_at <= end_date}
).to_csv_file(file_name, linesep: "\r\n", colsep: ",")
once the report is run I want to be able to do something to the records based on a different report_option [:variable] But I need to get that variable to the action that creates the file.
The problem:
My issues currently have 3 custom fields, let's say FieldA (select list), FieldB (irrelevant), and FieldC (text).
What needs to happen is that on save, FieldC takes the value of <FieldA>-<date in Ymd>-<number from database>
As an example, let's assume that FieldA has the value "Test", and today is the 8th of Jan 2015. FieldC should then be Test-20150108-001 where 001 comes from a custom table in the database, that's unique per value of FieldA, and resets every year.
What I've done to now:
I've used the command line script to generate a plugin via
ruby script/rails generate redmine_plugin subticket
And a model via
ruby script/rails generate redmine_plugin_model subticket subticket_ids fa:string lastnum:integer year:integer
( where fa is the value of FieldA, lastnum is the last number used for that value, and year is the current year for which the lastnum is applicable ).
I've then proceeded to prepend init.rb to add a hook listener in order to implenent the presave hooks:
require_dependency 'subticket_hooks'
And created the file lib/subticket_hooks.rb with the following content:
class SubticketHooksListener < Redmine::Hook::ViewListener
def controller_issues_edit_before_save(context={})
issue = context[:issue]
end
end
However, I cannot find any documentation on how to access/write the value of a custom field here. Still working on making the model work as well, but I assume the documentation is clear enough on that for me to experiment (of course any info is welcomed!)
Do note that this is way beyond my abilities since my core expertise is in a completely different language - take it slow!
I had the same task
My solution:
Every customizable redmine object has custom_field_values field, that value is array of CustomFieldValue. CustomFieldValue contains current value, custom field description and customized object.
Needed values i reads and alters by sort out. May be it's not best variant, but i acquainted with ruby language not so long ago.
Method for reading custom fields values:
def object_custom_field_value(object, field_name)
object.custom_field_values.each do |field|
if field.custom_field.name == field_name
return field.value
end
end
end
And for changing:
def object_custom_field_set_value(object, field_name, value)
object.custom_field_values.each do |field|
if field.custom_field.name == field_name
field.value = value
end
end
end
Hope this helps!
Get: object.custom_field_value(field.id)
Update: object.custom_field_values = {field.id => val}. Don't forget to save: object.save_custom_field_values. However it doesn't work for creating value, so check via object.custom_value_for(field.id).id?
Create/Update:
Easy. Just add a line object.custom_vield_values before update code. It returns list of values, and triggers creation of empty value. Example
u = User.find(1)
cf = CustomField.where('name', 'mobile phone').first
u.custom_field_values # returns values, triggers creation
u.custom_field_values = {cf.id = "+123456789"} # set value
u.save_custom_field_values # save
Docs: rubydoc
Updating a project's custom field named 'Email':
project = Project.find(1)
cv = CustomValue.where(customized_type: "Project", customized_id: project.id).includes(:custom_field).where(custom_fields: {type: 'ProjectCustomField', name: 'Email'}).first
cv.update value: 'email#mail.com'
I'm developing an event calendar, where each hour is a slot that allows users to sign one appointment.
Since there is a feature that allows users to update the slot (and also change date/time) I'd like to perform some check before to update the value, making sure that the slot is free.
So I ended up with a method like this:
if Event.find(:all, :conditions => ["start_at = ? AND event_calendar_id = ?", self.start_at, self.id])
errors.add :base, "You cannot save this appointment in that slot."
return false
end
By the way it creates issues when updating other fields without changing the datetime field, because it finds itself and raises the exception making impossible to update it.
Is there a way I can access database data such as the current id so I can filter out itself from the values, or check if the submitted datetime field is equal to the database one (so i can skip this check).
What's the best way to do this?
Thanks.
P.S. I'm using rails 3.2.3
To exclude self from the results just add a condition to your where excluding its id. Also save some memory and processor time by calling exists?, which just returns true or false instead of fetching an entire row and building a new object:
Event.where( :start_at => start_at,
:event_calendar_id => event_calendar.id ).
where( "id <> ?", id ).
exists?