Permalink
Browse files

reflecting on validations from rails into backbone models

  • Loading branch information...
1 parent 185be06 commit c72d5861c251ac94b0e9359f51db31fbc85b20a1 Chris Nelson committed Oct 1, 2012
@@ -3,14 +3,15 @@
#= require_tree ./models
#= require_tree ./views
#= require_tree ./routers
-#= require ./rails_metadata
+#= require rails_validations
window.Example =
Models: {}
Collections: {}
Routers: {}
Views: {}
-
+
$ ->
new Example.Routers.PeopleRouter()
- Backbone.history.start()
+ Backbone.history.start()
+ Backtastic.Rails.applyValidations(Example.Models)
@@ -1,11 +1,11 @@
class Example.Models.Person extends Backbone.Model
urlRoot: "/people"
-
- @validatePresenceOf "first_name"
-
- @validateFormatOf "last_name", pattern: /^J.*/
-
+
+ # @validatePresenceOf "first_name"
+
+ # @validateFormatOf "last_name", with: /^J.*/
+
class Example.Collections.PeopleCollection extends Backbone.Collection
model: Example.Models.Person
-
+
url: "/people"
@@ -3,7 +3,9 @@ class Example.Routers.PeopleRouter extends Backbone.Router
super
@people = new Example.Collections.PeopleCollection(peopleJson)
@occupations = new Example.Collections.OccupationsCollection(occupationsJson)
- @people.on "sync", => @navigate "people/list", trigger: true
+ @people.on "sync", @showPeople, @
+ @people.off null, null, @
+ => @navigate "people/list", trigger: true
@peopleView = new Example.Views.PeopleView(collection: @people, el: $("#people_view"))
@editPersonView = new Example.Views.EditPersonView(el: $("#edit_person"), occupations: @occupations)
@showPeople()
@@ -1,5 +1,5 @@
class Person < ActiveRecord::Base
validates_presence_of :first_name
-
+ validates_format_of :last_name, with: /^S.*/
belongs_to :occupation
end
@@ -1,6 +1,8 @@
require 'spec_helper'
-describe "schema_for" do
- Given(:person_schema) { Backtastic.schema_for(Person) }
- Then { person_schema["first_name"]["type"].should == :string }
+describe "rails_validations" do
+ Given(:validations) { Backtastic.validations_for(Person) }
+ Then { validations[:first_name].should_not be_empty }
+ Then { validations[:first_name]["presence"].should == {} }
+ Then { binding.pry; validations[:last_name]["format"][:with].should == "/^S.*/"}
end
@@ -0,0 +1,38 @@
+class BoringModel extends Backbone.Model
+
+describe "validation", ->
+ beforeEach ->
+ BoringModel.validate
+ first_name:
+ presence: {}
+ last_name:
+ format:
+ with: "/^S.*/"
+ @model = new BoringModel
+ @validationErrors = {}
+ @model.on "error", (model, errors) =>
+ @validationErrors = errors
+ describe "presence", ->
+ describe "when not matching", ->
+ beforeEach ->
+ @model.set first_name: ""
+ it "should validate presence of", ->
+ expect(@validationErrors.first_name.length).toEqual 1
+ describe "when matching", ->
+ beforeEach ->
+ @model.set first_name: "Bill"
+ it "should validate presence of", ->
+ expect(@validationErrors.first_name).not.toBeDefined()
+ describe "format", ->
+ describe "when not matching", ->
+ beforeEach ->
+ @model.set last_name: "Not smith"
+ it "should validate format", ->
+ expect(@validationErrors.last_name.length).toEqual 1
+ describe "when matching", ->
+ beforeEach ->
+ @model.set last_name: "Smith"
+ it "should validate format", ->
+ expect(@validationErrors.last_name).not.toBeDefined()
+
+
@@ -0,0 +1,9 @@
+Backtastic.Rails =
+ validations: {}
+
+<% ActiveRecord::Base.descendants.each do |model| %>
+Backtastic.Rails.validations.<%= model %> = <%= Backtastic.validations_for(model).to_json %>
+<% end %>
+
+Backtastic.Rails.applyValidations = (models) ->
+ model.validate(Backtastic.Rails.validations[name]) for name, model of models
@@ -1,42 +1,51 @@
Backtastic.Validators =
-
+
presence: (options) ->
(field, value) -> "is required" unless value?.length > 0
-
+
format: (options) ->
- (field, value) -> "must match specified format." unless value?.match(options?.pattern)
-
+ toRegExp = (str) ->
+ new RegExp(str.replace(/^\//, "").replace(/\/$/, ""))
+ pattern = if _.isRegExp(options?.with) then options?.with else toRegExp(options?.with)
+ (field, value) -> "must match specified format." unless value?.match(pattern)
+
Backtastic.Validation =
-
+
classMethods:
-
+
addValidator: (validator, field, options) ->
@validations or = {}
@validations[field] or= []
@validations[field].push Backtastic.Validators[validator]?(options)
validatePresenceOf: (field) ->
@addValidator("presence", field)
-
+
validateFormatOf: (field, options) ->
@addValidator("format", field, options)
-
+
+ validate: (validations) ->
+ @validations = {}
+ for field, fieldValidations of validations
+ for validationType, options of fieldValidations
+ @addValidator(validationType, field, options)
+
addError: (field, error) ->
@errors[field] or= []
@errors[field].push error
-
+
clearErrors: -> @errors = {}
-
+
validateAttribute: (attribute, value) ->
return unless @constructor.validations[attribute]
for validator in @constructor.validations[attribute]
error = validator(attribute, value)
@addError(attribute, error) if error
-
+
validate: (attributes) ->
@clearErrors()
return unless @constructor.validations
@validateAttribute(attr, value) for attr, value of attributes
@errors if _.keys(@errors).length > 0
-
+
Backtastic.include Backbone.Model, Backtastic.Validation
View
@@ -7,12 +7,24 @@
module Backtastic
class BacktasticEngine < Rails::Engine
end
-
- def self.schema_for(model)
- schema = {}
- model.to_s.constantize.columns.each do |col|
- schema[col.name] = {"type" => col.type }
+
+ def self.validations_for(model)
+ validations = {}
+ model.validators.each do |validator|
+ attribute = validator.attributes.first
+ validator_type = validator.class.to_s.gsub(/^ActiveModel::Validations::/, "").gsub(/Validator$/, "").downcase
+ validations[attribute] ||= {}
+ validations[attribute][validator_type] = options_from(validator)
end
- schema
+ validations
end
+
+ def self.options_from(validator)
+ options = validator.options.dup
+ options.each do |option, value|
+ options[option] = value.is_a?(Regexp) ? value.inspect : value
+ end
+ options
+ end
+
end

0 comments on commit c72d586

Please sign in to comment.