I'm working on a Rails project where I want to allow users to create individual notes, which are really just text fields at this time. With each note, the user can edit what they have previously written, but the old version is kept in a revision table. I'm trying to figure out the best way to approach this.
My initial thoughts are to have the following relationships:
class User < ActiveRecord::Base
has_many :notes
end
class Note < ActiveRecord::Base
has_many :note_revisions
belongs_to :user
end
class NoteRevision < ActiveRecord::Base
belongs_to :note_revision
end
The Note model will only contain a timestamp of when the note was first created. The NoteRevision model will contain the text, as well as a timestamp for each revision. This way, every time a new revision is made, a new entry is created into the NoteRevision table which is tracked through the Note table. Hopefully this makes sense!
First, does this look like a good way to do this? If so, I'm having trouble figuring out how the controller and view will present this information in one form. Are there any good tutorials or has someone seen anything similar that can point me in the right direction?
Thanks in advance!
I'd check out paper trail which will handle all the versioning for you and help you easily return the most current version. Behind the scenes it does something similar to what you're attempting to do but has been thoroughly tested and used by many people. It also benefits from active development.
Another option is the vestal_versions gem.
Railscasts.com has an episode on using it: http://railscasts.com/episodes/177-model-versioning
Related
I'm currently working on a product where for some reaasons we decided to destroy the email column from a specific table and then delegate that column to an associated table using active record delegate method
https://apidock.com/rails/Module/delegate
My question here will be about what is the approach to follow in order to make sure that all the where clauses that uses the email colum are also delegated as well. Because it's basically need a lot of time to check all the places where we used table.where(dropped_column: value)
Example
class Station < ActiveRecord::Base
has_one :contact
delegate :email, to: :contact
end
class Contact < ActiveRecord::Base
belongs_to :station
end
I know that it is possible to switch all the queries from Station.where(email: value) to Station.joins(:contact).where('contacts.email': value) but this approach will take very long and also where clause can be written in many different ways so searching throught the code source and updating all of them is not efficient enough to cover all the cases.
If anyone faced a similar situation and managed to solved in way that saves us time and bugs I will be very glad to hear what are the approaches you followed.
Thanks.
Rails version: '5.2.3'
what is the approach to follow in order to make sure that all the where clauses that uses the email column are also delegated as well
You cannot "delegate" SQL commands. You need to update them all.
I know that it is possible to switch all the queries from Station.where(email: value) to Station.joins(:contact).where('contacts.email': value) but this approach will take very long
Yep, that's what you'll need to do, sorry!
If anyone face a similar situation and managed to solved in way that saves us time and bugs I will be very glad to hear what are the approaches you followd.
Before dropping the column, you can first do this:
class Station < ActiveRecord::Base
self.ignored_columns = ['email']
has_one :contact
delegate :email, to: :contact
# ...
end
This way, you can stop the application from being able to access the column, without actually deleting it from the database (like a 'soft delete'), which makes it easy to revert.
Do this on a branch, and make all the specs green. (If you have good test coverage, you're done! But if your coverage is poor, there may be errors after deploying...)
If it goes wrong after deploying, you could revert the whole PR, or just comment out the ignored_columns again, temporarily, while you push fixes.
Then finally, once your application is running smoothly without errors, drop the column.
I am very new to rails. I am currently working on this questionnaire application that open once every few months. Responses given by the users will be saved in the database for a few survey rounds and then be archived and deleted afterwards.
Administrators are able to view the responses, and modify the existing list of survey questions for the next round of survey. Administrators have a fixed user account under users table as I am currently using devise for authentication.
The part that I can't wrap my head around is how do I make it such that modifying questions can be possible without affecting the existing responses of past questionnaire rounds. I have thought of duplicating the questions but I'm not too sure on how to implement it due to my lack of my understanding of rails.
This is the current model I have came up with:
class Questionnaire < ApplicationRecord
has_many :responses
end
class Response < ApplicationRecord
belongs_to :questionnaires
belongs_to :users
belongs_to :questions
end
class Question < ApplicationRecord
has_many :responses
end
class Users < ApplicationRecord
has_many :responses
end
#zhenbin I would suggest you to use something as act_as_versioned gem which keeps the version with every change in questions . So when ever new user gives survey latest question is pulled but when survey responses are pulled its pulled with its corresponding question
Why do you want to modify questions? If you make the next round of surveys, just create new ones.
Furthermore, in your model you can't write belongs_to with pluralized names as you will get an error, refer to http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association for more details.
I would suggest exporting the questions and answers from the database after each survey round, that way you can always modify questions at a later date without having to worry about maintaining older question/answer relationships.
It could (for example) be exported to a database dump file, or a CSV file (marketing departments love those). Exporting to a file in ruby isn't very complicated, and I think you'll be able to find many resources for doing so. For a CSV export, for instance, check out the CSV class.
Good luck!
I have built a very simple rails blog that is based on therapy-like sessions in real life. At the end of every blog post, a user can vote on the post where it says "How does that make you feel?"
I am nearly finished developing the application but I can't figure out how to make an expanded voting system.
There are 6 different emotion options that the user needs to be able to vote with (Happy, Sad, Angry, Inspired, Boring, Anxious). This means that one vote is not in any way better than the other. There are no positive and negative votes. They're just different.
So far, all the gems and tutorials I have come across feature a voting system that consists of two options. I need a way to implement 6.
Lastly, I would like to be able to count all of the total emotions belonging to a particular blog post and display the emotion with the most votes next to the title.
Has anyone ever tried something like this? After I figure out how to do this, I would like to make it into a gem if there isn't already one.
(I'm assuming a user just picks one vote per post, and that you're using the latest Rails 4.2)
Just create a new table that references both User and Post which has an integer field that we're going to use the new enum with, eg. Vote with integer field choice, so the model will be:
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :post
enum choice: %i[happy sad angry inspired boring anxious]
end
And your User and Post models will both has_many :votes
Then (as per the docs) you use Vote.choices to get a hash of name to integer (you'll use this to populate your view).
...and lastly, you'll get a hash of the count of emotions for a blog post with:
post.votes.group('votes.choice').count
I'm sure you can pick the most votes in there.
Update
The OP asked in a comment where I found this out, I thought my response to him might help others:
Hmm, well aside from the docs that I already linked you to in my answer, I follow the rails-core mailing list which announces and discusses upcoming features, I follow #rails on twitter where they announce all sorts of things, I read the release notes for new versions and I go through the release notes in the guides after major releases.
I'm looking for links or documentation about how to solve this rails data modeling issue. It doesn't seem straight forward.
I have a Report model with many columns such as wheel, break, bearing, etc. In each column I'm saving the condition of the part as "good" or "bad". This is the easy part.
However, if any of these columns are "bad" when the report is saved, I'm using an after_save callback to to create a new instance of the Correction model. In the Correction model I'm saving the report_id as well as the name of the part - wheel, break, etc.
Then I would like to be able to edit the Correction model at the same time as I edit the Report model using accepts_nested_attributes_for. Is this possible? How would I access the specific instance of the Correction model that corresponds to the Report column name? I'm not sure if I would be better off using a different approach for this.
I would be grateful for any links or docs which might help.
Thanks!
Looking at the documentation here: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html accepts_nested_attribute would enable you to create corrections for a given report at the same time that you create the report. But in your case you will create corrections only once the report has been created so i don't think you need to use accepts_nested_attribute.
I think what you would like to do is easy to do and depends how you implemented your Report and Correction model.
Let's suppose your model is similar to this:
class Report< ActiveRecord::Base
has_many :corrections
attr_accessible :wheel, :brake, etc...
after_save :create_corrections_if_bad_parts
def create_corrections_if_bad_parts
# For each part if one of them is changed to false, it create a new correction
self.attributes.keys.each do |key|
if send(key + "_changed?") and !self.attributes[key]
# Calling build will fill the report_id for you
correction = self.corrections.build(broken_part: key)
correction.save
end
end
end
end
class Correction < ActiveRecord::Base
belongs_to :report
attr_accessible :broken_part
end
This model assume you got one column for each parts but if you got too many part it might better to normalize the database or use a hash to store all part....
You can learn more about relationship over there: http://guides.rubyonrails.org/association_basics.html
I'm looking to implement a site wide comment/message feature into my apps entities. This will enable people to comment on the following modules
Newsletters
Reports
Tasks
and user to user (messaging)
My plan would be to make a foreign key called "entity_id" which doesn't relate to any single table. Instead, it's coupled with commentEntity_id which is a list of all the tables that can be commented on.
Example:
So a comment would have a CommentEntity which points to Reports and also an entity_id which, in this case, is the id of the Reports table.
The way I would build this is to make the following tables
Comment #along with user_id and a comment body:string, this will also have a commentEntity_id and a entity_id
CommentInvolvement # simply everyone involved (either by commenting on the entity, or in the case of user to user, **being** the entity)
CommentEntity # This is the join between the comment and the place
it's put.
This would be my solution in a PHP project, though I understand Rails requires a different way of thinking, so I would like to get the community's thoughts on this problem, and wheather this is the best way to tackle it?
Thanks
Yes, Rails supports this approach through Polymorphic associations
comment.rb
belongs_to :commentable, polymorphic: true
other models
has_many :comments, as: :commentable
Note: You have to add two columns in comments table commentable_id(Integer) and commentable_type(String)
you should also check out the great RailsCast regarding Polymorphic Associations
d