Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
{}[http://travis-ci.org/rubiety/has_draft] {}[https://gemnasium.com/rubiety/has_draft] {}[https://codeclimate.com/github/rubiety/has_draft]
== Has Draft
Allows for multiple "drafts" of a model which can be useful when developing:
This was built to be able to be tacked on to existing models, so the data schema doesn't need to change at all for the model this is applied to. Drafts are actually stored in a nearly-identical table and there is a has_one relationship to this. This separation allows the base model to really be treated just as before without having to apply conditions in queries to make sure you are really getting the "live" (non-draft) copy: Page.all will still only return the non-draft pages. This separate table is backed by a model created on the fly as a constant on the original model class. For example if a Page has_draft, a Page::Draft class will exist as the model for the page_drafts table.
== Installation
This gem supports ActiveRecord 3, 4, and 5.
In your Gemfile:
gem "has_draft"
== Basic Example
class InitialSchema < ActiveRecord::Migration
[:articles, :article_drafts].each do |table_name|
create_table table_name, :force => true do |t|
t.references :article if table_name == :article_drafts
t.string :title
t.text :summary
t.text :body
t.date :post_date
end
end
end
class Article < ActiveRecord::Base has_draft end
Article.draft_class => Article::Draft Article.with_draft.all => (Articles that have an associated draft) Article.without_draft.all => (Articles with no associated draft)
article = Article.create( :title => "My Title", :summary => "Information here.", :body => "Full body", :post_date => Date.today )
article.has_draft? => false
article.instantiate_draft!
article.has_draft? => true
article.draft => Article::Draft Instance
article.draft.update_attributes( :title => "New Title" )
article.replace_with_draft!
article.title => "New Title"
article.destroy_draft!
article.has_draft? => false
== Custom Options
class InitialSchema < ActiveRecord::Migration
[:articles, :article_copies].each do |table_name|
create_table table_name, :force => true do |t|
t.integer :news_article_id if table_name == :article_copies
t.string :title
t.text :summary
t.text :body
t.date :post_date
end
end
end
class Article < ActiveRecord::Base has_draft :class_name => 'Copy', :foreign_key => :news_article_id, :table_name => 'article_copies' end
class InitialSchema < ActiveRecord::Migration
[:elements, :element_drafts].each do |table_name|
create_table table_name, :force => true do |t|
t.integer :element_id if table_name == :element_drafts
t.string :title
t.text :content
t.string :type
end
end
end
class Element < ActiveRecord::Base class Draft < ActiveRecord::Base def element_icon_path 'assets/images/default.png' end end
module HasDraftCallbacks
def before_instantiate_draft
# Need to append ::Draft so that it knows to use the Draft class
self.draft.type = self.type + '::Draft'
end
def before_replace_with_draft
# We are storing drafts with the ::Draft on the end so we have to strip it
self.type = self.draft.type.split(':')[0]
end
end
end
class BlueElement < Element has_draft :belongs_to => :element, :extends => Element::Draft do def element_icon_path 'assets/images/blue.png' end end
include Element::HasDraftCallbacks
end
class UnknownElement < Element has_draft :belongs_to => :element, :extends => Element::Draft
include Element::HasDraftCallbacks
end
This allows us to call element_draft.element on any subclass of Element::Draft instead of needing to know to call element_draft.blue_element or element_draft.unknown_element.
Note: calling has_draft will have no effect if the parent class has already executed has_draft.
== Method Callbacks
There are three callbacks you can specify directly as methods:
class Article < ActiveRecord::Base has_draft
def before_instantiate_draft
# Do Something
end
def before_replace_with_draft
# Do Something
end
def before_destroy_draft
# Do Something
end
end
== Extending the Draft Class
Because you don't directly define the draft class, you can specify a block of code to be run in its context by passing a block to has_draft:
class Article < ActiveRecord::Base belongs_to :user
has_draft do
belongs_to :last_updated_user
def approve!
self.approved_at = Time.now
self.save
end
end
end
== Running Tests
This gem uses appraisal to test with different versions of the dependencies. See Appraisal first for which versions are tested.
$ bundle exec rake test
$ bundle exec rake all
FAQs
Unknown package
We found that has_draft demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.