ng_on_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 112566d25c565d9a8f6354967833d96c630284f4
4
+ data.tar.gz: 509e0df4fb071e2fbdae781ba2f255ae266b33f4
5
+ SHA512:
6
+ metadata.gz: 39650330a0379e048903523177fd690a09275481d715426b67c4c05ddf7bc43d350389c76696a88c22a965753f26f5c67f037e5dfa4672af3d6f09c3e2ab3e8b
7
+ data.tar.gz: 16f22ef0f8319ed9c2298f16f82512b6c19931904002764729ee21471a6c9d192cab13c42371f82d67c5ef759ad2173f0e65bd9cfccc34f3e75b73dce91d20aa
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,259 @@
1
+ ##### *This project is still in developement and uses MIT-LICENSE.*
2
+
3
+ -----------------------------------------------------------
4
+
5
+ ### NgOnRails
6
+
7
+ *A Rails inspired framework for using AngularJS with Rails*
8
+
9
+ The main motivations behind this gem is to standardize and simplify how AngularJS is integrated in a rails application.
10
+
11
+ I am just getting started but this does function *as-is*. Some things left to do:
12
+ * Write more specs!!!
13
+ * Create generators for controllers/services/(views?)
14
+ * (ViewHelper functions via shared service?)
15
+
16
+ I would love feed back (especially on convention choices) and possibly other contributers. Send me a note!
17
+
18
+ #### Overview
19
+
20
+ As time goes on generators for angular controllers and services (rails-models) will be added, as well as some view helpers and directives. For the time being however the the gem is rather simple.
21
+
22
+ It relies on two pieces of slight magic
23
+
24
+ 1. a "Rails" service that holds all your rails variables. This service automatically turns rails instance variables into json that can be used by Angular. For example the rails instance variable `@pages` will get mapped to `Rails.pages` that can be used by angular
25
+ ```
26
+ <div ng-repeat="page in Rails.pages">...
27
+ ```
28
+ To get this work you simply need to load the rails_service.js.erb partial
29
+ ```html.erb
30
+ <script>
31
+ = render( partial: 'angular_app/rails_service', formats: ['js'], locals: { ng_data: ng_data} )
32
+ </script>
33
+ ```
34
+ "rails_service.js.erb" calls the `locals_to_json` helper method to automatically turn instance variables into json. Here `ng_data` is a local rails variable used to customize how this is converted. This will be discussed in detail [below](#locals_to_json).
35
+ 2. Your angular views(partials) should be placed in app/views/angular_app. This solution is discussed in a handfull of places including [here](http://stackoverflow.com/questions/12116476/rails-static-html-template-files-in-the-asset-pipeline-and-caching-in-developmen), but the key parts are:
36
+ ```ruby
37
+ # routes.rb
38
+ scope :angular_app do
39
+ get ':path.html' => 'ng_on_rails#template', constraints: { path: /.+/ }
40
+ end
41
+
42
+ # ng_on_rails_controller.rb
43
+ def template
44
+ @path = params[:path]
45
+ render template: '/angular_app/' + @path, layout: nil
46
+ end
47
+ ```
48
+ You can then use the angular directive 'render'
49
+ ```javascript
50
+ NgOnRailsApp.directive(
51
+ "render",
52
+ function(){
53
+ return {
54
+ restrict: "AE",
55
+ transclude: true,
56
+ template: function(el,attrs){
57
+ return '<div ng_include="\'/angular_app/'+attrs.url+'.html\'"></div>'
58
+ }
59
+ }
60
+ }
61
+ )
62
+ ```
63
+ to load your angualar views in at 'app/views/angular_app'
64
+
65
+ #### Conventions
66
+
67
+ * Put Angular controllers/directives/... in a folder "angular\_app" in the assets directory. Similarly, as discussed above, the angular views(partials) are placed in a folder "angular\_app" in the views directory
68
+ ```
69
+ |-- app/
70
+ |-- assests/
71
+ |-- javascripts/
72
+ |-- angular_app/
73
+ |-- controllers/
74
+ |-- directives/
75
+ |-- services/
76
+ |- app.js
77
+ |-- views/
78
+ |-- angular_app/
79
+
80
+ ```
81
+ Files should be named/put in folders in the same maner that you would in Rails. For instance, if you have a Page model, you would have a pages_controller.js and a service page.js. Then under views you would have pages/{show.html,index.html,...}. *The way these views are handled makes them more like partials that views but for now at least I am not prefixing the name with and underscore "\_"*
82
+
83
+ * As for views, I try to have as little AngularJS outside of my angular_app folder. I will load the "Rails" service and set `ng-app="NgOnRailsApp"` in the application layout. Additionally I will usuallly have an angular `AppController` that is very limited in behavior that is part of the application layout. Again assuming I have a "Page" model I will handle the views like this
84
+
85
+ ```html
86
+ # app/views/pages/index.html
87
+ <!-- Apart from this render directive don't put any other angular in this file -->
88
+ <div render="true" url="pages/index" ng-init="pages=ctrl.rails.pages"></div>
89
+
90
+
91
+ # app/views/angular_app/pages/show.html
92
+ <div ng_controller="PagesController as ctrl">
93
+ <div ng-repeat="page in pages">
94
+ <div ng-show="ctrl.is_editing(page)">...
95
+ ```
96
+ *In the above, `ctrl.rails` has been set to the Rails service in the AppController*
97
+
98
+ * This brings up another point. Use the Controller-As syntax! I know there are people who aren't a fan. However in most apps where I am using angular there is a complicated Model structure. I necessarly want to edit all these things on a single page, though spread out through many partials. Controller-As really really helps keep the logic clear.
99
+
100
+
101
+ #### Angular Services for Rails Models
102
+ You are going to have a service for each rails model. I plan on adding generators but for now this is what my services look like
103
+
104
+ ```coffeescript
105
+ # app/assets/javascripts/angular_app/services/page.js.coffee
106
+ NgOnRailsApp.factory "Page", ($resource) ->
107
+ PageResource = $resource "/survey_link/questions/:id.json", {id: "@id"}, {
108
+ update:{method: "PUT"}
109
+ }
110
+ class Page extends PageResource
111
+ # place class and instance methods here if you want them.
112
+ ```
113
+
114
+
115
+ #### Angular Controllers for Rails Models
116
+ Simalarly you are going to have an angular controller for each rails model. Again, I plan on adding generators but for now an example is below. Note that I place all the REST methods in a rest object. Bridge is a service I use to pass data from one controller to another.
117
+
118
+ ```coffeescript
119
+ NgOnRailsApp.controller 'PagesController', ($scope,Page,Bridge) ->
120
+ # setup
121
+ ctrl = this
122
+ ctrl.bridge = Bridge
123
+ ctrl.data = {}
124
+
125
+ # initializers
126
+ ctrl.setPage = (page)->
127
+ ctrl.bridge.data.page = page
128
+ ctrl.setPages = (pages)->
129
+ ctrl.bridge.data.pages = pages
130
+
131
+ # rest methods
132
+ ctrl.rest =
133
+ index: ->
134
+ params = {}
135
+ Page.query(params).$promise.then (pages) ->
136
+ ctrl.bridge.data.pages = pages
137
+
138
+ show: (page_id)->
139
+ Page.get({id: page_id}).$promise.then (page) ->
140
+ ctrl.bridge.data.page = page
141
+ ctrl.bridge.data.page_versions = page.page_versions
142
+
143
+ new: (doc_id)->
144
+ ctrl.clear()
145
+ ctrl.data.activePage = {}
146
+ ctrl.data.activePage.doc_id = doc_id
147
+ ctrl.data.creating_new_page = true
148
+
149
+ create: ->
150
+ if !(ctrl.locked || ctrl.page_form.$error.required)
151
+ ctrl.locked = true
152
+ working_page = angular.copy(ctrl.data.activePage)
153
+ Page.save(
154
+ working_page,
155
+ (page)->
156
+ ctrl.bridge.data.pages ||= []
157
+ ctrl.bridge.data.pages.push(page)
158
+ ctrl.clear()
159
+ ctrl.locked = false
160
+ ,
161
+ (error)->
162
+ console.log("create_error:",error)
163
+ ctrl.clear()
164
+ ctrl.locked = false
165
+ )
166
+
167
+ edit: (page,doc_id) ->
168
+ ctrl.clear()
169
+ page.show_details = false
170
+ ctrl.data.activePage = page
171
+ ctrl.data.activePage.doc_id = doc_id
172
+ ctrl.data.editing_page = true
173
+
174
+ update: (page)->
175
+ if !(ctrl.locked || ctrl.page_form.$error.required)
176
+ ctrl.locked = true
177
+ page = ctrl.data.activePage unless !!page
178
+ working_page = angular.extend(angular.copy(page),ctrl.data.activePage)
179
+ Page.update(
180
+ working_page,
181
+ (page)->
182
+ # success handler
183
+ ctrl.locked = false
184
+ ,
185
+ (error)->
186
+ console.log("update_error:",error)
187
+ ctrl.locked = false
188
+ )
189
+ ctrl.clear()
190
+
191
+ delete: (index,page,pages)->
192
+ Page.delete(
193
+ page,
194
+ (page)->
195
+ pages ||= ctrl.bridge.data.pages
196
+ pages.splice(index,1)
197
+ ,
198
+ (error)->
199
+ console.log("delete_error:",error)
200
+ )
201
+ ctrl.clear()
202
+
203
+
204
+ # scope methods
205
+ ctrl.toggleDetails = (page)->
206
+ page.show_details = !page.show_details
207
+
208
+ ctrl.resort = (pages) ->
209
+ for page, index in pages
210
+ page.order_index = index + 1
211
+ Page.update(
212
+ page,
213
+ (page)->
214
+ # success handler
215
+ ,
216
+ (error)->
217
+ console.log("update_error:",error)
218
+ )
219
+
220
+ ctrl.clear = ->
221
+ ctrl.data.activePage = null
222
+ ctrl.data.creating_new_page = false
223
+ ctrl.data.editing_page = false
224
+
225
+ ctrl.is_editing = (page)->
226
+ (ctrl.data.editing_page && !!page && page.id == ctrl.data.activePage.id) ||
227
+ (ctrl.data.creating_new_page && !page)
228
+
229
+ # private methods
230
+ some_private_method = ->
231
+ console.log('nobody knows i exist')
232
+
233
+ return
234
+ ```
235
+ <a name="locals_to_json"></a>
236
+ #### Rails variables to Angular-able json.
237
+
238
+ As mentioned using the Rails-service you can get access to all your rails variables in angular.
239
+ ```html.erb
240
+ <script>
241
+ = render( partial: 'angular_app/rails_service', formats: ['js'], locals: { ng_data: ng_data} )
242
+ </script>
243
+ ```
244
+ Here, ng_data is a local rails variable that tells you have to do the conversion:
245
+
246
+ * if ng_data is nil all varibles will be converted with `.to_json` ( or if its a string/numeric with .to_s )
247
+ * if `ng_data['BUILD'].blank?` the default will be to use `.to_json` for conversion.
248
+ * if `ng_data['BUILD']=true` the default will be to look for a `.json` file in the app/views directory. It will guess the name and path to this file using the name of var. For instance, if we have @page it will look for the the file app/views/pages/page.json.
249
+ * if `ng_data[var_name].blank?` the conversion will use the defaults discussed above
250
+ * if `ng_data[var_name]={ path: 'path/to/file', as: model_name } it will use this info to try and find the build file. For instance, suppose I have a collection of pages called `@admin_pages`. Then `ng_data['admin_pages'] = { path: "survey_link/pages/pages", as: :pages }` will look for the file app/views/pages/pages.json seting the local variable `pages = @admin_pages`.
251
+
252
+ To understand it better look at [ng_on_rails_helper.rb](https://github.com/brookisme/ng_on_rails/blob/master/app/helpers/ng_on_rails_helper.rb).
253
+
254
+
255
+
256
+
257
+
258
+
259
+
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'NgOnRails'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
@@ -0,0 +1,3 @@
1
+ if (!window.NgOnRailsApp){
2
+ window.NgOnRailsApp = angular.module("NgOnRailsApp", ["ngResource","ngAnimate","ngSanitize"])
3
+ }
@@ -0,0 +1,12 @@
1
+ NgOnRailsApp.directive(
2
+ "render",
3
+ function(){
4
+ return {
5
+ restrict: "AE",
6
+ transclude: true,
7
+ template: function(el,attrs){
8
+ return '<div ng_include="\'/angular_app/'+attrs.url+'.html\'"></div>'
9
+ }
10
+ }
11
+ }
12
+ )
@@ -0,0 +1,3 @@
1
+ //
2
+ //= require_tree .
3
+ //
@@ -0,0 +1,6 @@
1
+ class NgOnRailsController < ApplicationController
2
+ def template
3
+ @path = params[:path]
4
+ render template: '/angular_app/' + @path, layout: nil
5
+ end
6
+ end
@@ -0,0 +1,77 @@
1
+ module NgOnRailsHelper
2
+ def locals_to_json ng_data
3
+ j = ActiveSupport::JSON
4
+ locals_hash = {}
5
+ instance_variable_names.each do |var_name|
6
+ unless !!var_name.match(/^@_/)
7
+ unless ignorables.include? var_name
8
+ name = var_name.gsub("@","")
9
+ instance_var = instance_variable_get(var_name)
10
+ unless instance_var.blank?
11
+ if ng_data.blank?
12
+ rv = instance_var
13
+ else
14
+ unless ng_data[name] == "IGNORE"
15
+ if !ng_data[name]
16
+ if !!ng_data["BUILD"]
17
+ rv = build(name,instance_var)
18
+ else
19
+ rv = instance_var
20
+ end
21
+ elsif ng_data[name]=="BUILD"
22
+ rv = build(name,instance_var)
23
+ elsif ng_data[name].class==Hash
24
+ path = ng_data[name][:path]
25
+ model_name = ng_data[name][:as] || name
26
+ rv = build(model_name,instance_var,path)
27
+ end
28
+ end
29
+ end
30
+ unless !defined?(rv) || rv.blank?
31
+ if (rv.is_a?(String) && !is_json?(rv)) || rv.is_a?(Numeric)
32
+ locals_hash[name] = rv
33
+ elsif is_json?(rv)
34
+ locals_hash[name] = j.decode(rv)
35
+ else
36
+ locals_hash[name] = j.decode(rv.to_json)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ return locals_hash.to_json
44
+ end
45
+
46
+ private
47
+
48
+ def ignorables
49
+ [
50
+ "@view_renderer",
51
+ "@view_flow",
52
+ "@output_buffer",
53
+ "@virtual_path",
54
+ "@fixture_connections",
55
+ "@example",
56
+ "@fixture_cache",
57
+ "@loaded_fixtures",
58
+ "@controller",
59
+ "@request",
60
+ "@output_buffer",
61
+ "@rendered"
62
+ ]
63
+ end
64
+
65
+ def is_json? string
66
+ begin
67
+ !!JSON.parse(string)
68
+ rescue
69
+ false
70
+ end
71
+ end
72
+
73
+ def build name, var, path=nil
74
+ path = name unless !!path
75
+ render(path.to_s+'.json', name.to_sym => var)
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ NgOnRailsApp.service('Rails', function(){
2
+ return JSON.parse('<%= raw(locals_to_json(ng_data)) %>')
3
+ });
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Rails.application.routes.draw do
2
+ # AngularJS Templates
3
+ scope :angular_app do
4
+ get ':path.html' => 'ng_on_rails#template', constraints: { path: /.+/ }
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ require "ng_on_rails/engine"
2
+ module NgOnRails
3
+ end
@@ -0,0 +1,11 @@
1
+ module NgOnRails
2
+ class Engine < ::Rails::Engine
3
+ initializer 'ng_on_rails.load_static_assets' do |app|
4
+ app.middleware.use ::ActionDispatch::Static, "#{root}/app"
5
+ end
6
+
7
+ initializer "ng_on_rails.view_helpers" do
8
+ ActionView::Base.send :include, NgOnRailsHelper
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module NgOnRails
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :ng_on_rails do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ng_on_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brookie Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A Rails inspired framework for using AngularJS with Rails
56
+ email:
57
+ - brookwilliams@laborvoices.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - app/assets/javascripts/app.js
66
+ - app/assets/javascripts/directives/shared.js.erb
67
+ - app/assets/javascripts/ng_on_rails.js
68
+ - app/controllers/ng_on_rails_controller.rb
69
+ - app/helpers/ng_on_rails_helper.rb
70
+ - app/views/angular_app/_rails_service.js.erb
71
+ - config/routes.rb
72
+ - lib/ng_on_rails.rb
73
+ - lib/ng_on_rails/engine.rb
74
+ - lib/ng_on_rails/version.rb
75
+ - lib/tasks/ng_on_rails_tasks.rake
76
+ homepage: http://www.laborvoices.com
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.2.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: A Rails inspired framework for using AngularJS with Rails
100
+ test_files: []