How to create a changelog? - ruby-on-rails

I'm building a site that shows changes in deals that we have in our db. For example, if a deals status changes from pending to win, I want to show it, and if the value goes up or down, I want to show it, that kind of thing. Also, if you open the overview page, I want it to show the history of changes. So I need some kind of change logging, to be able to look in the past. How do I do this?
It is a rails project, but I think that's irrelevant.

I doubt there is any generic solution to this problem.
You can roll out your own. Start by considering all objects that need change logging. How many types are there? How often do you expect changes to occur? This will help you estimate the potential number of changes throughput you'll need to be dealing with. If there aren't too many, just stick them into database. If you are generating a lot, try storing to comma-separated-value file.
I have implemented a similar system before. I had 3 types of changes: 1) property value change, 2) adding of a value to a list, 3) removing value from a list.
I used the following format, stored in a log file:
//For type 1)
1,2011/01/01 00:00:00,MyObject,myProperty,oldValue,newValue
//For type 2)
2,2011/01/01 00:00:00,MyObject,myListProperty,addedValue
//For type 3)
3,2011/01/01 00:00:00,MyObject,myListProperty,removedValue
This captured most information I needed. The value parts were just some user-readable summary of the changed/added/removed property value.

Paper Trail Gem
Since you're on Rails, take a look at the PaperTrail gem. It does exactly what you're looking for and is beautifully built. You'll just need to add in a callback so that your overview page knows that a change occurred. But for the history of a model, just use the built-in PaperTrail functionality.

Related

how to display a list of report-bots that are available to me

I used to use "iter_dialogs" to get a list of available chats. But this method has stopped working. Can you suggest an alternative? And is it possible to get a list of report-bots to write to them later? I will be very glad of any help.
iter_dialogs() doesn't work anymore, as it has been replaced by get_dialogs(). See Pyrogram's Release Notes for v2:
Iter_ methods have been removed:* This means there is now only one way of iterating through items by using the respective get_* methods which are all turned into generators. Some of the methods have been renamed as well:
iter_history becomes get_chat_history().
iter_chat_members becomes get_chat_members().
iter_dialogs becomes get_dialogs().
iter_profile_photos becomes get_chat_photos().
As for your second question about report bots, I have no idea what you're talking about there. You might want to edit your question to add more detail.

Umbraco7 - ContentService.SaveAndPublishWithStatus VS ContentService.SendToPublication

I have an application that uses a combination of ContentService.Saved & ContentService.Saving to extend Umbraco to manage content.
I have two websites in one Umbraco installation I am using those methods to keep content up to date in different parts of the tree.
So far I have got everything working the way I wanted to.
Now I want to add a feature that: depending on which Umbraco User is logged in, will either publish the content or simply send it for approval.
So I have changed some lines of code from:
cs.SaveAndPublishWithStatus(savedNode, 0, false)
To this:
cs.SendToPublication(savedNode);
Now the problem that I am finding is that unlike the SaveAndPublishWithStatus() method, the cs.SendToPublication(); doesn't have the option of passing false so that a save event is not raised. So I get into an infinite loop.
When I attach the debugger and manually stop the infinite loop the first time it calls cs.SendToPublication(savedNode); I get exactly the behavior I want.
Any ideas about how I can get round this problem? Is there a different method that I should be using?
You are correct in saying that it currently isn't possible to set raiseEvents to false when sending an item to publication - that's a problem.
I've added that overload in v. 7.6 (http://issues.umbraco.org/issue/U4-9490).
However considering that you need this now, an interim solution could be that you make sure your code is only run once when triggered by the .Saved / .Saving events.
One way to do this would be to check the last saved date (UpdateDate) in your code. If the content was saved within the last second of the current save operation, you know that this is a save event triggered by the save happening in SendToPublication action. Then you also know that the item has already been sent to publication and that this doesn't need to be done again - thereby preventing the endless loop from happening.

Resolving conflicts between automated updates and manual overrides

This is a bit of a complex, abstract question, so forgive me if it's not specific enough.
I've encountered a specific type of problem numerous times: That on one hand, a data source is used to update a certain data structure in an automated fashion at regular intervals, but on the other hand, stakeholders want to be able to manually override the automated entries.
Example:
You have a list of products, which are kept up-to-date (title, description, etc.) by some automated script which uses external data sources (product databases, etc.).
Let's say that in your data source you have a toaster "Freshtoast XYZ 300" and if its name changes to "FreshToast! XYZ-300", you want to propagate that update into your own (differently structured) product model.
At the same time, if a co-worker doesn't like the name "Freshtoast XYZ 300" and wants to change it to "Toaster XYZ 300 by Freshtoast" (manually), you don't want to override that change automatically (he would get angry), but you also don't want to simply ignore the updated name, since if the co-worker knew about the change, he'd adjust the name to "Toaster XYZ-300 by FreshToast!".
What's the best method to "consider" updated data sources - even for overridden data - while still allowing manual override?
PS: I'm using mostly Ruby / Rails, but I guess the question is very general. Also, to be clear, automated updates are the rule, while manual overrides are the exception in this scenario. So let's say 200,000 products get updated every single day, only 20 of which have manually overridden titles. So, for example, having to approve every single update is not an option.
Here goes nothing...
Hands off approach: Add a string column to products table that contains a serialized list of user-touched columns. Anytime a user touches a column in the products table, put it in the serialized list. When the automatic updater hits that record it checks the list for columns it should ignore.
Hand-wringing micro-manager approach: Use a versioning library (e.g. vestal_versions gem) and add a user_id column to the products table. Anytime a user-touched record is automatically updated, send them a notification and allow them to view a before/after which they can approve or reject.

How to create a tagging system like on Stack Overflow or Quora

I want to create a tagging system like seen here on Stack Overflow or on Quora. It'll be its own model, and I'm planning on using this autocomplete plugin to help users find tags. I have a couple of questions:
I want tags to be entirely user-generated. If a user inputs a new tag by typing it and pressing an "Add" button, then that tag is added to the db, but if a user types in an existing tag, then it uses that one. I'm thinking of using code like this:
def create
#video.tags = find_or_create_by_name(#video.tags.name)
end
Am I on the right track?
I'd like to implement something like on Stack Overflow or Quora such that when you click a tag from the suggested list or click an "Add" button, that tag gets added right above the text field with ajax. How would I go about implementing something like that?
I know this is kind of an open-ended question. I'm not really looking for the exact code as much as a general nudge in the right direction. Of course, code examples wouldn't hurt :)
Note I am NOT asking for help on how to set up the jQuery autocomplete plugin... I know how to do that. Rather, it seems like I'll have to modify the code in the plugin so that instead of the tags being added inside the text field, they are added above the text field. I'd appreciate any direction with this.
mbleigh's acts_as_taggable_on gem is a feature-complete solution that you should definitely look into a little more closely. The implementation is rock-solid and flexible to use. However, it is mostly concerned with attaching tags to objects, retrieving tags on objects, and searching for tagged items. This is all backend server stuff.
Most of the functionality you are looking to change (based on your comments) is actually related more to your front-end UI implementation, and the gem doesn't really do much for you there. I'll take your requests one-by-one.
If user inputs a new tag, that tag
gets added, if user inputs an
existing tag, the existing tag gets
used. acts_as_taggable_on does this.
Click a tag from suggested list to
add that tag. This is an
implementation issue - on the
back-end you'll need to collect the
suggested list of tags, then display
those in your presentation as links
to your processing function.
Autocomplete as user enters
potential tag. You'll use the jQuery
autocomplete plugin against a list
of items pulled off the tags table.
With additional jQuery, you can
capture when they've selected one of
the options, or completed entering
their new tag, and then call the
processing function.
Restrict users to entering only one
tag. This will be your UI
implementation - once they've
entered or selected a tag, you
process it. If they enter two words
separated by a comma, then before or
during processing you have to either
treat it as one tag, or take only
the text up to the first comma and
discard the rest.
When you process the addition of a
tag, you will have to do two things.
First, you'll need to handle the UI
display changes to reflect that a
tag has been entered/chosen. This
includes placing the tag in the
"seleted" area, removing it from the
"available" display, updating any
counters, etc. Second, you'll need
to send a request to the server to
actually add the tag to the object
and persist that fact to the
database (where the taggable gem will take over for you). You can either do this via
an individual AJAX request per tag,
or you can handle it when you submit
the form. If the latter, you'll need
a var to keep the running list of
tags that have been added/removed
and you'll need code to handle
adding/removing values to that var.
For an example of saving tags while editing but not sending to server/db until saving a form, you might take a look at the tagging functionality on Tumblr's new post page. You can add/remove tags at will while creating the post, but none of it goes to the database until you click save.
As you can see, most of this is on you to determine and code, but has very little to do with the backend part. The gem will take care of that for you quite nicely.
I hope this helps get you moving in the right direction.
The more I try to force the acts-as-taggable-on gem to work the more I think these are fundamentally different types of problems. Specifically because of aliases. The gem considers each tag to be its own special snowflake, making it difficult to create synonyms. In some cases it doesn't go far enough, if you want the Tag to have a description you'd need to edit the given migrations (which isn't hard to do).
Here's what I'm considering implementing, given the trouble I've had implementing via the gem. Let's assume you want to create a tagging system for Technologies.
Consider the following psuedo code, I haven't yet tested it.
rails g model Tech usage_count::integer description:text icon_url:string etc. Run the migration. Note the
Now in the controller you will need to increment usage_count each time something happens, the user submits a new question tagged with given text.
rails g model Name::Tech belongs_to:Tech name:string
Name::Tech model
belongs_to :tech
end
Then you could search via something like:
search = Name::Tech.where("name LIKE :prefix", prefix: "word_start%")
.joins(:tech)
.order(usage_count: desc)
.limit(5)
This is starting point. It's fundamentally different from the gem, as each tag is just a string on its own, but references a richer data table on the back end. I'll work on implementing and come back to update with a better solution.

auto_complete_for: prevent the first item from being auto-selected

The auto_complete_for dealio from script.aculo.us is great an all, but is there a way for me to selectively disable the fact that it always auto-selects the first item in the list?
The problem is that, if I want to type my own entry that is new, and novel, I don't want the first item in the list to be auto-selected. The reason is because when I TAB out of the field, it selects, and fills the text box with that first item.
I got around that, somewhat, by making the first item in the list the same as what I'm typing, but that's not perfect either, because the auto_complete list doesn't always update with every keystroke, depending on how fast I type. I've tried setting the list refresh rate to the lowest value (1 millisecond) but no go.
What I really want is an option in "auto_complete_for" that doesn't select that first item at all - the same way that Google Instant doesn't automatically select the first suggested search phrase - you have to arrow-down to select one.
Maybe I can do this via an HTML option that I'm missing?
Looking at the source, there doesn't appear to be an option for that, but I bet if you changed line 284 of controls.js to this.index = -1; it would do what you want.
Otherwise, it might be time to look for a different autocomplete widget.
If your requirements are too far away from the available plugin, then I guess there is no point in tinkering around. Its best to write your own JS code.
You might want to consider this: https://github.com/laktek/jQuery-Smart-Auto-Complete
or this : https://github.com/reinh/jquery-autocomplete
I'll add another alternative that works great with Rails 3:
http://github.com/crowdint/rails3-jquery-autocomplete
I recently implemented auto complete for more than a field for Rails 2.0.2.
The plugin I used is:- https://github.com/david-kerins/auto_complete . Not sure if it supports Rails 3.
I have also encountered issues on implementing the above scenario and have posted questions( Implementing auto complete for more than one field in Rails ; Implementing a OnClick kind of functionality and formatting wrt Rails Partial-Views ) on stackoverflow for the same, I have been lucky on getting things working for me based on my requirement.
Kindly refer to these questions, they might have relevance to your requirement.

Resources