I am looking for a Ruby/Rails tool that will help me accomplish the following:
I would like to store the following string, and ones similar to it, in my database. When an object is created, updated, deleted, etc., I want to run through all the strings, check to see if the CRUD event matches the conditions of the string, and if so, run the actions specified.
When a new ticket is created and it's category=6 then notify user 1234 via email
I am planning to create an interface that builds these strings, so it doesn't need to be a human-readable string. If a JSONish structure is better, or a tool has an existing language, that would be fantastic. I'm kinda thinking something along the lines of:
{
object_types: ['ticket'],
events: ['created', 'updated'],
conditions:'ticket.category=6',
actions: 'notify user',
parameters: {
user:1234,
type:'email'
}
}
So basically, I need the following:
Monitor CRUD events - It would be nice if the tool had a way to do this, but Ican use Rails' ModelObservers here if the tool doesn't natively provide it
Find all matching "rules" - This is my major unknown...
Execute the requested method/parameters - Ideally, this would be defined in my Ruby code as classes/methods
Are there any existing tools that I should investigate?
Edit:
Thanks for the responses so far guys! I really appreciate you pointing me down the right paths.
The use case here is that we have many different clients, with many different business rules. For the rules that apply to all clients, I can easily create those in code (using something like Ruleby), but for all of the client-specific ones, I'd like to store them in the database. Ideally, the rule could be written once, stored either in the code, or in the DB, and then run (using something Resque for performance).
At this point, it looks like I'm going to have to roll my own, so any thoughts as to the best way to do that, or any tools I should investigate, would be greatly appreciated.
Thanks again!
I don't think it would be a major thing to write something yourself to do this, I don't know of any gems which would do this (but it would be good if someone wrote one!)
I would tackle the project in the following way, the way I am thinking is that you don't want to do the rule matching at the point the user saves as it may take a while and could interrupt the user experience and/or slow up the server, so...
Use observers to store a record each time a CRUD event happens, or to make things simpler use the Acts as Audited gem which does this for you.
1.5. Use a rake task, running from your crontab to run through the latest changes, perhaps every minute, or you could use Resque which does a good job of handling lots of jobs
Create a set of tables which define the possible rules a user could select from, perhaps something like
Table: Rule
Name
ForEvent (eg. CRUD)
TableInQuestion
FieldOneName
FieldOneCondition etc.
MethodToExecute
You can use a bit of metaprogramming to execute your method and since your method knows your table name and record id then this can be picked up.
Additional Notes
The best way to get going with this is to start simple then work upwards. To get the simple version working first I'd do the following ...
Install acts as audited
Add an additional field to the created audit table, :when_processed
Create yourself a module in your /lib folder called something like processrules which roughly does this
3.1 Grabs all unprocessed audit entries
3.2 Marks them as processed (perhaps make another small audit table at this point to record events happening)
Now create a rules table which simply has a name and condition statement, perhaps add a few sample ones to get going
Name: First | Rule Statement: 'SELECT 1 WHERE table.value = something'
Adapt your new processrules method to execute that sql for each changed entry (perhaps you want to restrict it to just the tables you are working with)
If the rule matched, add it to your log file.
From here you can extrapolate out the additional functionality you need and perhaps ask another question about the metaprogramaming side of dynamically calling methods as this question is quite broad, am more than happy to help further.
I tend to think the best way to go about task processing is to setup the process nicely first so it will work with any server load and situation then plug in the custom bits.
You could make this abstract enough so that you can specify arbitrary conditions and rules, but then you'd be developing a framework/engine as opposed to solving the specific problems of your app.
There's a good chance that using ActiveRecord::Observer will solve your needs, since you can hardcode all the different types of conditions you expect, and then only put the unknowns in the database. For example, say you know that you'll have people watching categories, then create an association like category_watchers, and use the following Observer:
class TicketObserver < ActiveRecord::Observer
# observe :ticket # not needed here, since it's inferred by the class name
def after_create(ticket)
ticket.category.watchers.each{ |user| notify_user(ticket, user) }
end
# def after_update ... (similar)
private
def notify_user(ticket, user)
# lookup the user's stored email preferences
# send an email if appropriate
end
end
If you want to store the email preference along with the fact that the user is watching the category, then use a join model with a flag indicating that.
If you then want to abstract it a step further, I'd suggest using something like treetop to generate the observers themselves, but I'm not convinced that this adds more value than abstracting similar observers in code.
There's a Ruby & Rules Engines SO post that might have some info that you might find useful. There's another Ruby-based rules engine that you may want to explore that as well - Ruleby.
Hope that this helps you start your investigation.
Related
I am building a rails app and the data should be reset every "season" but still kept. In other words, the only data retrieved from any table should be for the current season but if you want to access previous seasons, you can.
We basically need to have multiple instances of the entire database, one for each season.
The clients idea was to export the database at the end of the season and save it, then start fresh. The problem with this is that we can't look at all of the data at once.
The only idea I have is to add a season_id column to every model. But in this scenario, every query would need to have where(season_id: CURRENT_SEASON). Should I just make this a default scope for every model?
Is there a good way to do this?
If you want all the data in a single database, then you'll have to filter it, so you're on the right track. This is totally fine, as data is filtered all the time anyway so it's not a big deal. Also, what you're describing sounds very similar to marking data as archived (where anything not in the current season is essentially archived), something that is very commonly done and usually accomplished (I believe) via setting a boolean flag on every record to true or false in order to hide it, or some equivalent method.
You'll probably want a scope or default_scope, where the main downside of a default_scope is that you must use .unscoped in all places where you want to access data outside of the current season, whereas not using a default scope means you must specify the scope on every call. Default scopes can also seem to get applied in funny places from time to time, and in my experience I prefer to always be explicit about the scopes I'm using (i.e. I therefore never use default_scope), but this is more of a personal preference.
In terms of how to design the database you can either add the boolean flag for every record that tells whether or not that data is in the current season, or as you noted you can include a season_id that will be checked against the current season ID and filter it that way. Either way, a scope of some sort would be a good way to do it.
If using a simple boolean, then either at the end of the current season or the start of the new season, you would have to go and mark any current season records as no longer current. This may require a rake task or something similar to make this convenient, but adds a small amount of maintenance.
If using a season_id plus a constant in the code to indicate which season is current (perhaps via a config file) it would be easier to mark things as the current season since no DB updates will be required from season to season.
[Disclaimer: I'm not familiar with Ruby so I'll just comment from the database perspective.]
The problem with this is that we can't look at all of the data at once.
If you need to keep the old versions accessible, then you should keep them in the same database.
Designing "versioned" (or "temporal" or "historized") data model is something of a black art - let me know how your model looks like now and I might have some suggestions how to "version" it. Things can get especially complicated when handling connections between versioned objects.
In the meantime, take a look at this post, for an example of one such model (unrelated to your domain, but hopefully providing some ideas).
Alternatively, you could try using a DBMS-specific mechanism such as Oracle's flashback query, but this is obviously not available to everybody and may not be suitable for keeping the permanent history...
I'm in the process of creating a product configurator. Trouble is that each product has many components, which are themselves configurable. Imagine you're configuring a computer when buying it.
The dependencies sometimes apply when a component is selected, or when a quantity of a component, or even a combination of both. It all becomes very complicated at some point, and is not consistent across products, as each is its own universe in a sense.
Oh, and these rules change all the time, so coding them in the app is not really an option for me.
I was hoping to be able to store the code of a method called validate in the database.
Each configuration would have it's own version of validate, which would be stored as a text in the db, and could be changed if/when required.
Is is possible to do this? How can i take text and have rails actually execute whatever this text says?
For example i have this:
irb(main):246:0> #h= Configuration.find(1).rule
=> "def getmax3(inputarray)\n #maxpos = 0\n inputarray.each do |h|\n if #maxpos < h.position\n #maxpos = h.position\n end\n end\n 1\n end"
which obviosly isn't code. The method above is of course just a test as I'm trying to figure things out.
(Oh and I know it must be horrible practice to do this, but I really can't think of another way)
Thanks a lot!
Yes it is an horrible practice :)
If you had simple and stabilized rules to implement, you could store some variables in a dedicated table and use those variables in your rules; since it looks like you don't really know what is going to happen about those rules, be ready to accept any challenge by using a tested and proven workflow.
Here's my suggestion:
Setup an automatic deploy procedure using capistrano and other tools
Write your rules in a dedicated validation library
Code & test rules, commit and deploy
Defining a DSL can make your life easier, if you are committed in the long term to manipulate such rules and you could not be the only one in charge of such task; observe how the rules are changed over a good amount of time and you will know if having a dedicated DSL is a good thing or a waste of time.
I might be misunderstanding your problem, but if you could get that code out of the database and into files that can be tested and versioned, you'll be in a much happier place. Without knowing the intricacies of your models, it's hard to say what the best approach would be, but I guarantee one is out there.
I've used Single Table Inheritance in the past for modeling complex systems that have related components which share common properties and behavior. You might be able to use this approach with your application. STI basically says you have a parent class, in your case Configuration, and subclasses, that all reside in the same table. If there is shared behavior among some but not all of the subclasses, then you can move that code to modules and include in the classes that need it.
Basic parent class would just inherit from ActiveRecord:
class Configuration < ActiveRecord::Base
end
Then each subclass would have its logic defined within it:
class Component < Configuration
def getmax3(inputarray)
#maxpos = 0
inputarray.each do |h|
if #maxpos < h.position
#maxpos = h.position
end
end
1
end
end
I'm not saying this is the direction you want to go, but hopefully it will make you think about other ways of modeling your system.
We are creating a system in Ruby on Rails and we want to be able to offer our users a bit of control about notifications and actions that can take place when some pre-defined trigger occurs. In addition, we plan on iterating through imported data and allowing our users to configure some actions and triggers based on that data.
Let me give you a few examples to better clarify:
Trigger - Action
------------------------------------------------------------------------
New Ticket is Created - User receives an e-mail
New Ticket Parsed for Keyword 'evil' - Ticket gets auto-assigned to a
particular group
User Missed 3 Meetings - A ticket is automatically created
Ideally, we would like some of the triggers to be configurable. For instance, the last example would possibly let you configure how many meetings were missed before the action took place.
I was wondering what patterns might help me in doing this event/callback situation in Ruby on Rails. Also, the triggers and actions may be configurable, but they will be predefined; so, should they be hard coded or stored in the database?
Any thoughts would be greatly appreciated. Thanks!
Update 1: After looking at it, I noticed that the badges system on SO is somewhat similar, based on these criteria, I want to do this action. It's slightly different, but I want to be able to easily add new criteria and actions and present them to the users. Any thoughts relating to this?
I think that what you are looking for are the Observers.
In your examples the Observers could handle the first and the third example (but not the second one, since an Observer only observes the object, not interact with it, even though it is technically possible).
Some code to show how I mean:
class TicketObserver < ActiveRecord::Observer
def after_create(ticket)
UserMailer.deliver_new_ticket_notification
end
end
class UserObserver < ActiveRecord::Observer
def after_update(user)
Ticket.new if user.recently_missed_a_meeting and user.missed_meetings > 3
end
end
And then add the observers to environment.rb
config.active_record.observers = :user_observer, :ticket_observer
Of course you will have to fill in the logic for the missed_meetings, but one detail to mention.
Since the after_update will trigger after every time that the user is being updated, the recently_missed_a_meeting attribute is useful. I usually follow the thinking of restful-authentication and have an instance variable that is being set to true everytime I want to trigger that row. That can be done in a callback or in some custom logic depends on how you track the meetings.
And for the second example, I would put it in a before_update callback, perhaps having the keywords in a lookup table to let users update which words that should trigger the move to a specific group.
You should look at the "callback" methods in Rails
For docs see - Callbacks
Your first rule would be implemented via the after_create method.
If you want them to be configurable, I would suggest using a model / table to store the possible actions and doing a lookup within the callback.
If this is high volume, be sure to consider caching the configuration since it would end up doing a db lookup on each callback.
Maybe something like a state-machine can help. Try AASM gem for RoR.
thanks for your time first...after all the searching on google, github and here, and got more confused about the big words(partition/shard/fedorate),I figure that I have to describe the specific problem I met and ask around.
My company's databases deals with massive users and orders, so we split databases and tables in various ways, some are described below:
way database and table name shard by (maybe it's should be called partitioned by?)
YZ.X db_YZ.tb_X order serial number last three digits
YYYYMMDD. db_YYYYMMDD.tb date
YYYYMM.DD db_YYYYMM.tb_ DD date too
The basic concept is that databases and tables are seperated acording to a field(not nessissarily the primary key), and there are too many databases and too many tables, so that writing or magically generate one database.yml config for each database and one model for each table isn't possible or at least not the best solution.
I looked into drnic's magic solutions, and datafabric, and even the source code of active record, maybe I could use ERB to generate database.yml and do database connection in around filter, and maybe I could use named_scope to dynamically decide the table name for find, but update/create opertions are bounded to "self.class.quoted_table_name" so that I couldn't easily get my problem solved. And even I could generate one model for each table, because its amount is up to 30 most.
But this is just not DRY!
What I need is a clean solution like the following DSL:
class Order < ActiveRecord::Base
shard_by :order_serialno do |key|
[get_db_config_by(key), #because some or all of the databaes might share the same machine in a regular way or can be configed by a hash of regex, and it can also be a const
get_db_name_by(key),
get_tb_name_by(key),
]
end
end
Can anybody enlight me? Any help would be greatly appreciated~~~~
Case two (where only db name changes) is pretty easy to implement with DbCharmer. You need to create your own sharding method in DbCharmer, that would return a connection parameters hash based on the key.
Other two cases are not supported right away, but could be easily added to your system:
You implement sharding method that knows how to deal with database names in your sharded dabatase, this would give you an ability to do shard_for(key) calls to your model to switch db connection.
You add a method like this:
class MyModel < ActiveRecord::Base
db_magic :sharded => { :sharded_connection => :my_sharding_method }
def switch_shard(key)
set_table_name(table_for_key(key)) # switch table
shard_for(key) # switch connection
end
end
Now you could use your model like this:
MyModel.switch_shard(key).first
MyModel.switch_shard(key).count
and, considering you have shard_for(key) call results returned from the switch_shard method, you could use it like this:
m = MyModel.switch_shard(key) # Switch connection and get a connection proxy
m.first # Call any AR methods on the proxy
m.count
If you want that particular DSL, or something that matches the logic behind the legacy sharding you are going to need to dig into ActiveRecord and write a gem to give you that kind of capability. All the existing solutions that you mention were not necessarily written with your situation in mind. You may be able to bend any number of solutions to your will, but in the end you're gonna have to probably write custom code to get what you are looking for.
Sounds like, in this case, you should consider not use SQL.
If the data sets are that big and can be expressed as key/value pairs (with a little de-normalization), you should look into couchDB or other noSQL solutions.
These solutions are fast, fully scalable, and is REST based, so it is easy to grow and backup and replicate.
We all have gotten into solving all our problems with the same tool (Believe me, I try to too).
It would be much easier to switch to a noSQL solution then to rewrite activeRecord.
I have a simple model called Party with a corresponding table called parties. There's also a controller with all the usual CRUD actions and so on. This model is used in a website and only one admin user is allowed to edit the parties - everyone else is allowed to call GET actions (index, show). Nothing special so far.
Now I need to do the following: The admin would like to choose a single Party at a time for special presentation (the selected Party is showing up on the start page of the application). The most important thing is, that there's only ONE party at time selected.
How would you solve this problem? Boolean Flag in Party model? Save the selection (id of the party) somewhere outside the database? Implement a new model with a has_one relation to Party (seems like overkill to me)?
I hope my explanation is good enough to understand the issue.
A simple "front_page" attribute would suffice or another model like you mentioned, using the has_one relationship would be fine as well.
Using another model would allow you to maintain some more information, like how long should it remain on the front page (expiration date?) or how many times it was featured (assuming a party can be featured twice). It really depends on other requirements for your system.
You also might be able to get away with a simple implementation of the Singleton pattern as well. There's a quick description on the Rails Wiki of making an ActiveRecord object a Singleton (see below): http://wiki.rubyonrails.org/rails/pages/TipsAndTricks
Making a singleton ActiveRecord object
If you have a table with just one
entry, useful for keeping track of a
number sequence for databases without
sequences, you can use the singleton
module included with ruby like so:
require 'singleton'
class Master < ActiveRecord::Base
include Singleton
def initialize(args=nil) super(args) if record = Master.find(:first)
self.attributes = record.attributes end end def next_tracking_number increment!
(:current_tracking_number) current_tracking_number end def
self.next_tracking_number instance.next_tracking_number
end
end
Update:
This is a very poor code example (was copied and pasted from the Rails Wiki, which had no formatting). I would highly recommend the [Ruby Design Patterns] book which tackles many of the GoF design patterns in greater detail (while making them applicable to Ruby applications). But Google should return you some good resources for using the Singleton pattern in Ruby.2
I would go for the boolean flag and create nested singleton resource (promoted), which I would implement in PartiesController itself (set_promoted_party and get_promoted_party actions). For these I would create two new routes:
PUT /parties/promoted/:party_id # to set the promoted party
GET /parties/promoted/:party_id # to get the promoted_party
I would add a second model that had a has_one relationship in order to keep the app RESTful and simple. Also, this way, you can keep a history of special Parties, and track other meaningful information related to the special parties.
Personally I'm very strong on data integrity being enforced by my database so would probably add that extra table and enforce it as a foreign key constraint there.
It can seem like overkill, but is the only* solution that prevents data integrity issues.
Could you maybe add it as a field to the admin table/model - which would be an enforced foreign key to the party table?
*Another solution would be a database trigger that checks no other rows are the selected party but I tend to shy away from such solutions.
Keep it simple. Put a promoted_party.yml file in your config directory that the controllers write to and read from. The contents can be as simple as this:
---
party_id: 123
Done. If you need more integrity or fancier relationships later, implement that later, not now.
For deployments, just make sure the file is symlinked to a shared directory to survive application upgrades.