In Rails, when a record is to be deleted, I want to maintain a separate table for such deleted records (that in structure would be analogous to the former).
One way to achieve this would be to obviously copy the structure, validations and associations from the first model and paste it into the deleted items model. This would, however, result in a lot of code redundancy and is not a scalable solution.
Is there a way to achieve this in Rails without much (or any) code redundancy
or a solution that might be more scalable than the one mentioned
above?
I am using Ruby 1.9.3-p125 and Rails 3.2.
UPDATE
I did consider using an additional is_deleted column in the table, however, I decided against it because I didn't want this table to get too big and messy with deleted posts. I don't intend to really access these deleted posts - these are merely stored for record-keeping or archival purposes. Adding this column would also make accessing this table slower and more importantly, I am afraid that I may miss the check is_deleted == false in some SQL condition somewhere - even if I include this check in the default_scope of the model.
It is good idea to move them to separate table so that your primary table have less number of records and performance is not decreased by time.
Use Rails ActiveRecord Callback for deletion i.e.
before_destroy :move_to_trash
.
.
def move_to_trash
Trash.create!(self)
end
In this way, when a record is deleted, its copy will be created in Trash table.
Well, basically you want to keep the records and not throw them away. So you may want to just mark them "deleted" and tweak the logic in your code to not consider those records while retrieving them.
Add a 'deleted' column in your original table. Set the default scope of the model to exclude deleted records.
Related
I get flat files once a week that have a few 100k rows. I would like to turn them into a relational model system in Rails since there are about five columns that are fairly static and would make sense for a different model that would then be linked back into the main table as a foreign key.
Is there was a quick way to check if an entry already exists, and if so, look it up and put the foreign key in the main model, and if not, create a new entry in the second model and then reference it in the main model.
I can turn the above paragraph into code but wanted to know if there is a simple 'few lines' Ruby or Rails implementation.
Just for the sake of merging my comment and #anton-z 's.
You can use activerecord-import for doing bulk operations, and ActiveRecord's find_or_create_by to do the checking.
I want to allow users to create drafts of several models (such as article, blog post etc). I am thinking of implementing this by creating a draft model for each of my current models (such as articleDraft, blogpostDraft etc.). Is there a better way to do this? Creating a new model for every existing model that should support drafts seems messy and is a lot of work.
I think the better was is to have a flag in the table (ex: int column called draft), to identify if the record is a draft or not.
Advantages of having such a column with out a separate table, as I can see:
It's easy to make your record non-draft (just change the flag)
you will not duplicate data (because practically you will have the same in draft and non-draft records)
coding will be easy, no complex login
all the data will be in one place and hence less room for error
I've been working on Draftsman, a Ruby gem for creating a draft state of your ActiveRecord data.
Draftsman's default approach is to store draft data for all drafted models in a single drafts table via a polymorphic relationship. It stores the object state as JSON in an object column and optionally stores JSON data representing changes in an object_changes column.
Draftsman allows for you to create a separate draft model for each model (e.g., article_drafts, blog_post_drafts) if you want. I agree that this approach is fairly cumbersome and error-prone.
The real advantage to splitting the draft data out into separate models (or to just use a boolean draft flag on the main table, per sameera207's answer) is that you don't end up with a gigantic drafts table with tons of records. I'd offer that that only becomes a real problem when your application has a ton of usage though.
All that to say that my ultimate recommendation is to store all of your draft data in the main model (blog) or a single drafts table, then separate out as needed if your application needs to scale up.
Check out the Active Record Versioning category at The Ruby Toolbox. The current leader is Paper Trail.
I'd go down the state machine route. You can validate each attribute when the model's in a certain state only. Far easier than multiple checkboxes and each state change can have an action (or actions) associated with it.
Having a flag in the model has some disadvantages:
You can not save as draft unless the data is valid. Sure, you can skip validations in the Rails model, but think about the "NOT NULL" columns defined in the database
To find the "real" records, you have to use a filter (like "WHERE draft = FALSE"). This can slow down query performance.
As an alternative, check out my gem drafting. It stores drafts for different models in a separate table.
I want to alter a record, but I don't want to read it out of the database first, because frankly I don't see the point. It's huge and across a network that is slow and expensive.
Can it be done (easily)?
Lets say I have a record with 100 fields (for arguments sake) and I want to alter one field in the table. I have a really bad connection to the database (this is true) because it's housed on a different box and there's nothing I can do to change this.
Right now I pull down the record and rails validates its contents (because I have serialized bits) I then alter one field (one of the hundred depending on X condition) and save the record again. Which I suppose writes the whole record to the database again, with no knowledge of the fact that I only changed one small bit. (this last bit is assumption)
Now to change one record it's sending a huge amount of data across the network, and it could be that I'm only changing one small small thing..
Also it's doing two queries on the database. First the select * then the update..
So my question.. are there smarter base classes that do this right, to write without read?
Top of my head I would think a setter method for each field with a bool flag for changed.
When saving, walk the flags and where true... Does this happen now, if so how do I make use of it?
Rails models have the update method, which does a SQL select then an SQL update.
Its use is simple (suppose you have a model named Person)
Person.update(person_id, :user_name => 'New Name')
The drawback is that you have to know beforehand the person id.
But then, you will always have to do a query to find out that. You could write your own SQL to change the column value, with a WHERE clause that searches for the param you have.
Rails models have the update_all method, which does only a SQL update without loading the data.
But I wouldn't recommend using it because it doesn't trigger any callbacks or validations that your model may have.
You could use the update_all like this:
Book.update_all "author = 'David'", "title LIKE '%Rails%'"
ps: examples were all taken from the Rails official documentation. If you search for update, or update_all, you'll find both methods in no time.
Take a look there, it's a good place to find out what rails can do.
Rails API link
It's not obvious from the documentation, but update_all is the answer to this question.
Book.where(id: 123).update_all(title: "War and Peace")
results in exactly one query:
UPDATE `books` SET `books`.`title` = "War and Peace" WHERE `books`.`id` = 123
It's been a while since this question was asked, but this is so for Rails 4/5/6.
I am not sure exactly what I should name this question. I just started server-side programming and I need some help.
All the tutorials I have read so far on RoR deal with creating a pre-defined table and with pre-defined fields (id, name, email, etc etc). They use ActiveRecord as base class and saving to db is handled automatically by superclass.
What I am trying to program is something that allows user-defined table with fields. So think of this way. The web UI will have an empty table, the user will name the table, and add columns (field), and after that, add rows, and then later save it. How would I implement this? I am not asking for details, just an overview of it. As I said, all the tutorials I have read so far deal with pre-defined tables with fields where the ActiveRecord subclass is predefined.
So in a nutshell, I am asking, how to create tables in db on runtime, and add fields to the tables.
Hope I was clear, if not, please let me know and i will try to elaborate a bit more.
Thanks.
Unless you're building a DB administration tool (and even maybe then), allowing the user direct access to the database layer in the way you're suggesting is probably a bad idea. Apart from issues of stability and security, it'll get really slow if your users are creating lots of tables.
For instance, if you wanted to search for a certain value across 100 of your users' tables, you'd have to run 100 separate queries. The site would get exponentially slower the more user tables that were created.
A saner way to do it might be to have a Table model like this
class Table < ActiveRecord::Base
has_many :fields
has_many :rows
end
Every table would have fields attached to it, and rows to store the corresponding data (which would be encoded somehow).
However, as #Aditya rightly points out, this is not really beginner stuff!
I agree with previous answers generally speaking. It's not clear from your question why you want to create a table at runtime. It's not really obvious what the advantage of doing this would be. If you are just trying to store data that seems to fit into a table with rows and columns, why not just store it as an array in a field of your user table. If your user is allowed to create many tables, then you could have something like
class User < ActiveRecord::Base
has_many :tables
end
and then each table might have a field to store a serialized array. Or you could go with Alex's suggestion - the best choice really depends on what you are going to do with the data, how often it changes, whether you need to search it and so on ...
You can create a database as shown in tutorials which stores name of tables and their columns name those your user want. Then you can have worker (which can be build using Redis and Resque, here is simple Tut on Resque and Redis) and have those worker run migration (write migration with variables and use params to replace them) for you for new table in DB as soon as new entry is made in database. Tell me if you have questions on this.
I have a class Question which has a lot of assocated models. On one page on my app i list a summary of all the current questions, with various info from associated records. Ultimately this is a hash of values that i then just print out into a csv-style row (i'll call this the 'row hash' from hereon)
I now have a requirement to only show the changes to questions (or their associated data) over a given period. I'm currently deliberating the best way to do this. Here's some ideas i've had so far, i'd welcome any feedback, thoughts, suggestions etc.
1) Approach 1 - acts_as_audited
This was my first thought as i've used this before in other apps. The porblem with aaa though is that it only tracks changes to the record's data (ie it doesn't care if the associations change). So, i could audit all of the associated records as well but then trying to piece together what had changed by tying different audit records together sounds like a nightmare.
2) Save the old and new hash out into serialized fields: ie
- when someone goes to the question/edit page, i calculate the current row hash and save it in a serialized field "old_data" in the question table. Then after they save the question i calculate the new current row hash and save it into a serialized field "new_data" in the question table. Also, i compare the two serialized hashes and save the differences into another serialized hash field 'changes'. Now to do my report i just look for questions updated in the last x days and output their changes data.
3) make a view
- i make a view which corresponds to the data that i want to output (ie that amalgamates all the data that i pull into my report). Then i track changes to the view - somehow. I'm not sure how exactly i would do that.
I'm leaning towards option 2 right now.
Any other thoughts/comments? grateful for any suggestions - max.
So, like you said, you only want to show changes to the records between time x and time y, right? This would seem perfect to me using the acts_as_audited plugin because you end up with a table of changes, right? So make a has_many_through association from Question to all these related tables, then search it for related changes, where date created is after time X. This would return a list of changes. From there, you could connect this list back to the parent object if you need to, or whatever - but it in the end seems like a more reasonable thing to search. You're not looking for a list of related objects, after all, you're looking for a list of changes, so having a table of changes seems a reasonable way to accomplish that?
Hey I had a similar problem, check this out. If you can, go with Mongoid or Mongomapper, embedded versioned documents are sweet.
Thanks guys. I ended up rolling my own solution because what i really needed to do was to capture changes in the results of various methods called on the object, some of which involved associated objects. I wasn't so much interested in the associated objects as (for example) a text string generated as a result of looking at a few different associated objects. I had methods to do all of this already so i really just needed to track changes in the results of calling these methods.
None of the plugins i saw could really do that simply and effectively, so i ended making a table called states which just holds a serialized hash with results of all of these method calls. This gets saved when the record is altered and saved or when any of the relevant associated objects get altered and saved. Then i have some methods to return the differences between different saved state records. It works well for my needs. Thanks very much for your advice anyway.