feedbackable 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in feedbackable.gemspec
4
+ gemspec
@@ -0,0 +1,29 @@
1
+ Installation:
2
+
3
+ 1) Add gem to your Gemfile, as:
4
+ gem 'feedbackable'
5
+ then run
6
+ bundle install
7
+
8
+ 2) Your email settings must be preconfigured before using feedbackable gem
9
+
10
+ 3) Run generators:
11
+ rails g feedbackable:install
12
+ rake db:migrate
13
+ rails g feedbackable:views
14
+
15
+ 4) Add admin_email configuration parameter to your application.rb:
16
+ config.feedbackable.admin_email = 'your@admin_email.com'
17
+ 5) Add to your application.js
18
+ //= require jqmodal
19
+ //= require init
20
+ To your application.css
21
+ *= require jqmodal
22
+ 6) Add to your model:
23
+ has_feedback
24
+ And to your view:
25
+ <a href="#" class="jqModal">Add feedback</a>
26
+ <div class="jqmWindow" id="dialog">
27
+ <a href="#" class="jqmClose">X</a>
28
+ <%= render :partial => 'feedbacks/form', :locals => { :feedbackable => @your_model_instance } %>
29
+ </div>
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ class FeedbacksController < ApplicationController
2
+
3
+ def create
4
+ pf = params[:feedback]
5
+ @feedback = Feedback.new(
6
+ :subject => pf[:subject],
7
+ :feed_text => pf[:feed_text],
8
+ :contact_email => pf[:contact_email]
9
+ )
10
+ @feedback.feedbackable_type = pf[:feedbackable_type]
11
+ @feedback.feedbackable_id = pf[:feedbackable_id]
12
+
13
+ respond_to do |format|
14
+ if @feedback.save
15
+ format.js
16
+ # Need some load mask in the future
17
+ UserMailer.feedback_send(pf[:subject], pf[:feed_text], pf[:contact_email]).deliver
18
+ else
19
+ format.js { render :partial => 'errors' }
20
+ end
21
+ end
22
+ end
23
+
24
+ end
File without changes
@@ -0,0 +1,8 @@
1
+ class UserMailer < ActionMailer::Base
2
+ def feedback_send(subject, body, from)
3
+ @subject = subject
4
+ @body = body
5
+ @from = from
6
+ mail(:to => Feedbackable::config.admin_email, :from => from, :subject => "You've got new feedback!")
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class Feedback < ActiveRecord::Base
2
+
3
+ belongs_to :feedbackable, :polymorphic => true
4
+
5
+ attr_accessible :subject, :feed_text, :contact_email
6
+ validates_presence_of :subject, :feed_text, :feedbackable, :presence => true
7
+ validates :contact_email, :presence => true,
8
+ :length => {:minimum => 3, :maximum => 254},
9
+ :format => {:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i}
10
+ end
@@ -0,0 +1 @@
1
+ $("#new_feedback-notice").html('<div><%= escape_javascript(@feedback.errors.map {|k,v| "#{k.to_s.titleize} #{v}"}.join('<br/>')).html_safe %></div>');
@@ -0,0 +1,26 @@
1
+ <%= form_for Feedback.new, :remote => true do |f| %>
2
+ <div id='new_feedback-notice'></div>
3
+
4
+ <div class="field">
5
+ <%= f.label :subject %>:<br />
6
+ <%= f.text_field :subject %>
7
+ </div>
8
+
9
+ <div class="field">
10
+ <%= f.label :contact_email %>:<br />
11
+ <%= f.text_field :contact_email %>
12
+ </div>
13
+
14
+ <div class="field">
15
+ <%= f.label :feed_text %>:<br />
16
+ <%= f.text_area:feed_text %>
17
+ </div>
18
+
19
+ <%= f.hidden_field :feedbackable_type, :value => feedbackable.class.name %><br />
20
+ <%= f.hidden_field :feedbackable_id , :value => feedbackable.id %><br />
21
+
22
+ <div class="actions">
23
+ <%= f.submit "Send feedback" %>
24
+ </div>
25
+
26
+ <% end %>
@@ -0,0 +1,3 @@
1
+ $("#new_feedback")[0].reset();
2
+ $('#dialog').jqmHide();
3
+ alert("Thanks, your feedback has been sent");
@@ -0,0 +1,8 @@
1
+ <h3>Hi!</h3>
2
+ <p><i>New feedback:</i></p>
3
+ <b>From:</b>
4
+ <%= @from %><br/>
5
+ <b>Subject:</b>
6
+ <%= @subject %><br/>
7
+ <b>Feedback text:</b>
8
+ <%= @body %>
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+
3
+ resources :feedbacks
4
+
5
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "feedbackable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "feedbackable"
7
+ s.version = Feedbackable::VERSION
8
+ s.authors = ["Marat Galiev"]
9
+ s.email = ["kazanlug@gmail.com"]
10
+ s.homepage = "http://www.smartapps.ru"
11
+ s.summary = %q{Add feedback to your models}
12
+ s.description = %q{Adding feedback action to model}
13
+
14
+ s.rubyforge_project = "feedbackable"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ end
@@ -0,0 +1,26 @@
1
+ require "feedbackable/version"
2
+ require "feedbackable/railtie"
3
+ require "feedbackable/engine"
4
+ require "feedbackable/active_record_extension"
5
+
6
+ module Feedbackable
7
+
8
+ def self.configure(&block)
9
+ yield @config ||= Feedbackable::Configuration.new
10
+ end
11
+
12
+ def self.config
13
+ @config
14
+ end
15
+
16
+ class Configuration #:nodoc:
17
+ include ActiveSupport::Configurable
18
+ config_accessor :admin_email
19
+ def param_name
20
+ config.param_name.respond_to?(:call) ? config.param_name.call() : config.param_name
21
+ end
22
+ end
23
+
24
+ ActiveRecord::Base.extend(Feedbackable::ActiveRecordExtension)
25
+
26
+ end
@@ -0,0 +1,7 @@
1
+ module Feedbackable
2
+ module ActiveRecordExtension
3
+ def has_feedback(options = {})
4
+ # some options must be here, like feedbacks table name etc
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module Feedbackable
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,14 @@
1
+ require 'rails'
2
+
3
+ module Feedbackable
4
+ class Railtie < ::Rails::Railtie
5
+ config.feedbackable = ActiveSupport::OrderedOptions.new
6
+
7
+ initializer "feedbackable.configure" do |app|
8
+ Feedbackable.configure do |config|
9
+ config.admin_email = app.config.feedbackable[:admin_email] || 'admin@example.com'
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Feedbackable
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,42 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module Feedbackable
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ source_root File.expand_path("../templates", __FILE__)
10
+
11
+ desc "Generates migration for Feebacker"
12
+
13
+ def self.orm
14
+ Rails::Generators.options[:rails][:orm]
15
+ end
16
+
17
+ def self.orm_has_migration?
18
+ [:active_record].include? orm
19
+ end
20
+
21
+ def self.next_migration_number(dirname)
22
+ if ActiveRecord::Base.timestamped_migrations
23
+ migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
24
+ migration_number += 1
25
+ migration_number.to_s
26
+ else
27
+ "%.3d" % (current_migration_number(dirname) + 1)
28
+ end
29
+ end
30
+
31
+ def copy_migration
32
+ migration_template 'install.rb', 'db/migrate/install_feedbackable.rb'
33
+ end
34
+
35
+ def add_assets
36
+ ad = File.expand_path("../../../../vendor/assets", __FILE__)
37
+ directory ad, "vendor/assets"
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ class InstallFeedbackable < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :feedbacks do |t|
4
+ t.string :subject, :limit => 20
5
+ t.text :feed_text
6
+ t.references :feedbackable, :polymorphic => true
7
+ t.string :contact_email
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :feedbacks, :feedbackable_type
12
+ add_index :feedbacks, :feedbackable_id
13
+ end
14
+
15
+ def self.down
16
+ drop_table :feedbacks
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+
3
+ module Feedbackable
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../../../../app/views', __FILE__)
7
+
8
+ def copy_or_fetch
9
+ filename_pattern = File.join self.class.source_root, "*"
10
+ Dir.glob(filename_pattern).map {|f| File.basename f}.each do |f|
11
+ directory f.to_s, "app/views/#{f}"
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1 @@
1
+ require 'feedbackable'
@@ -0,0 +1,38 @@
1
+ require 'active_record'
2
+ require 'action_controller/railtie'
3
+
4
+ # database
5
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'mysql2', :database => 'marat_development', :username => "root", :password => "777777"}}
6
+ # ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
7
+ ActiveRecord::Base.establish_connection('test')
8
+
9
+ # config
10
+ app = Class.new(Rails::Application)
11
+ app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
12
+ app.config.session_store :cookie_store, :key => "_myapp_session"
13
+ app.config.active_support.deprecation = :log
14
+ app.initialize!
15
+
16
+ # models
17
+ class Order < ActiveRecord::Base
18
+ has_feedback
19
+ end
20
+
21
+ # routes
22
+ app.routes.draw do
23
+ resources :feedbacks
24
+ end
25
+
26
+ #migrations
27
+ ActiveRecord::Base.silence do
28
+ ActiveRecord::Migration.verbose = false
29
+ ActiveRecord::Schema.define :version => 0 do
30
+ create_table "feedbacks", :force => true do |t|
31
+ t.string :subject, :limit => 20
32
+ t.text :feed_text
33
+ t.references :feedbackable, :polymorphic => true
34
+ t.string :contact_email
35
+ t.timestamps
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,6 @@
1
+ # Simulate a gem providing a subclass of ActiveRecord::Base before the Railtie is loaded.
2
+
3
+ require 'active_record'
4
+
5
+ class GemDefinedModel < ActiveRecord::Base
6
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Feedback do
4
+
5
+ it "should create valid feedback object" do
6
+ order = Order.new
7
+ order.save
8
+ feedback = Feedback.new
9
+ feedback.subject = "Test subject"
10
+ feedback.feed_text = "Cool order!"
11
+ feedback.contact_email = 'from@test.com'
12
+ feedback.feedbackable = order
13
+ feedback.save.should be true
14
+ end
15
+
16
+ it "should not create feedback without data" do
17
+ feedback = Feedback.new
18
+ feedback.save.should be false
19
+ end
20
+
21
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+
5
+ require 'rails'
6
+ require 'active_record'
7
+ require 'feedbackable'
8
+ require File.dirname(__FILE__) << '/../app/models/feedback'
9
+
10
+ require 'fake_app'
@@ -0,0 +1,6 @@
1
+ $().ready(function() {
2
+ $('#dialog').jqm();
3
+ $('.jqmClose').on('click',function() {
4
+ $("#new_feedback-notice").html('');
5
+ });
6
+ });
@@ -0,0 +1,69 @@
1
+ /*
2
+ * jqModal - Minimalist Modaling with jQuery
3
+ * (http://dev.iceburg.net/jquery/jqModal/)
4
+ *
5
+ * Copyright (c) 2007,2008 Brice Burgess <bhb@iceburg.net>
6
+ * Dual licensed under the MIT and GPL licenses:
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ * http://www.gnu.org/licenses/gpl.html
9
+ *
10
+ * $Version: 03/01/2009 +r14
11
+ */
12
+ (function($) {
13
+ $.fn.jqm=function(o){
14
+ var p={
15
+ overlay: 50,
16
+ overlayClass: 'jqmOverlay',
17
+ closeClass: 'jqmClose',
18
+ trigger: '.jqModal',
19
+ ajax: F,
20
+ ajaxText: '',
21
+ target: F,
22
+ modal: F,
23
+ toTop: F,
24
+ onShow: F,
25
+ onHide: F,
26
+ onLoad: F
27
+ };
28
+ return this.each(function(){if(this._jqm)return H[this._jqm].c=$.extend({},H[this._jqm].c,o);s++;this._jqm=s;
29
+ H[s]={c:$.extend(p,$.jqm.params,o),a:F,w:$(this).addClass('jqmID'+s),s:s};
30
+ if(p.trigger)$(this).jqmAddTrigger(p.trigger);
31
+ });};
32
+
33
+ $.fn.jqmAddClose=function(e){return hs(this,e,'jqmHide');};
34
+ $.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};
35
+ $.fn.jqmShow=function(t){return this.each(function(){t=t||window.event;$.jqm.open(this._jqm,t);});};
36
+ $.fn.jqmHide=function(t){return this.each(function(){t=t||window.event;$.jqm.close(this._jqm,t)});};
37
+
38
+ $.jqm = {
39
+ hash:{},
40
+ open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=(parseInt(h.w.css('z-index'))),z=(z>0)?z:3000,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});if(h.a)return F;h.t=t;h.a=true;h.w.css('z-index',z);
41
+ if(c.modal) {if(!A[0])L('bind');A.push(s);}
42
+ else if(c.overlay > 0)h.w.jqmAddClose(o);
43
+ else o=F;
44
+
45
+ h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):F;
46
+ if(ie6){$('html,body').css({height:'100%',width:'100%'});if(o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),"(_=(document.documentElement.scroll"+y+" || document.body.scroll"+y+"))+'px'");}}
47
+
48
+ if(c.ajax) {var r=c.target||h.w,u=c.ajax,r=(typeof r == 'string')?$(r,h.w):$(r),u=(u.substr(0,1) == '@')?$(t).attr(u.substring(1)):u;
49
+ r.html(c.ajaxText).load(u,function(){if(c.onLoad)c.onLoad.call(this,h);if(cc)h.w.jqmAddClose($(cc,h.w));e(h);});}
50
+ else if(cc)h.w.jqmAddClose($(cc,h.w));
51
+
52
+ if(c.toTop&&h.o)h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);
53
+ (c.onShow)?c.onShow(h):h.w.show();e(h);return F;
54
+ },
55
+ close:function(s){var h=H[s];if(!h.a)return F;h.a=F;
56
+ if(A[0]){A.pop();if(!A[0])L('unbind');}
57
+ if(h.c.toTop&&h.o)$('#jqmP'+h.w[0]._jqm).after(h.w).remove();
58
+ if(h.c.onHide)h.c.onHide(h);else{h.w.hide();if(h.o)h.o.remove();} return F;
59
+ },
60
+ params:{}};
61
+ var s=0,H=$.jqm.hash,A=[],ie6=$.browser.msie&&($.browser.version == "6.0"),F=false,
62
+ i=$('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0}),
63
+ e=function(h){if(ie6)if(h.o)h.o.html('<p style="width:100%;height:100%"/>').prepend(i);else if(!$('iframe.jqm',h.w)[0])h.w.prepend(i); f(h);},
64
+ f=function(h){try{$(':input:visible',h.w)[0].focus();}catch(_){}},
65
+ L=function(t){$()[t]("keypress",m)[t]("keydown",m)[t]("mousedown",m);},
66
+ m=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);if(r)f(h);return !r;},
67
+ hs=function(w,t,c){return w.each(function(){var s=this._jqm;$(t).each(function() {
68
+ if(!this[c]){this[c]=[];$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return F;});}this[c].push(s);});});};
69
+ })(jQuery);
@@ -0,0 +1,37 @@
1
+ /* jqModal base Styling courtesy of;
2
+ Brice Burgess <bhb@iceburg.net> */
3
+
4
+ /* The Window's CSS z-index value is respected (takes priority). If none is supplied,
5
+ the Window's z-index value will be set to 3000 by default (via jqModal.js). */
6
+
7
+ .jqmWindow {
8
+ display: none;
9
+
10
+ position: fixed;
11
+ top: 17%;
12
+ left: 50%;
13
+
14
+ margin-left: -300px;
15
+ width: 600px;
16
+
17
+ background-color: #EEE;
18
+ color: #333;
19
+ border: 1px solid black;
20
+ padding: 12px;
21
+ }
22
+
23
+ .jqmOverlay { background-color: #000; }
24
+
25
+ /* Background iframe styling for IE6. Prevents ActiveX bleed-through (<select> form elements, etc.) */
26
+ * iframe.jqm {position:absolute;top:0;left:0;z-index:-1;
27
+ width: expression(this.parentNode.offsetWidth+'px');
28
+ height: expression(this.parentNode.offsetHeight+'px');
29
+ }
30
+
31
+ /* Fixed posistioning emulation for IE6
32
+ Star selector used to hide definition from browsers other than IE6
33
+ For valid CSS, use a conditional include instead */
34
+ * html .jqmWindow {
35
+ position: absolute;
36
+ top: expression((document.documentElement.scrollTop || document.body.scrollTop) + Math.round(17 * (document.documentElement.offsetHeight || document.body.clientHeight) / 100) + 'px');
37
+ }
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feedbackable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Marat Galiev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &80727290 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *80727290
25
+ description: Adding feedback action to model
26
+ email:
27
+ - kazanlug@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.md
35
+ - Rakefile
36
+ - app/controllers/feedbacks_controller.rb
37
+ - app/mailers/.gitkeep
38
+ - app/mailers/user_mailer.rb
39
+ - app/models/feedback.rb
40
+ - app/views/feedbacks/_errors.js.erb
41
+ - app/views/feedbacks/_form.html.erb
42
+ - app/views/feedbacks/create.js.erb
43
+ - app/views/user_mailer/feedback_send.html.erb
44
+ - config/routes.rb
45
+ - feedbackable.gemspec
46
+ - lib/feedbackable.rb
47
+ - lib/feedbackable/active_record_extension.rb
48
+ - lib/feedbackable/engine.rb
49
+ - lib/feedbackable/railtie.rb
50
+ - lib/feedbackable/version.rb
51
+ - lib/generators/feedbackable/install_generator.rb
52
+ - lib/generators/feedbackable/templates/install.rb
53
+ - lib/generators/feedbackable/views_generator.rb
54
+ - lib/init.rb
55
+ - spec/fake_app.rb
56
+ - spec/fake_gem.rb
57
+ - spec/feedbackable/feedback_test.rb
58
+ - spec/spec_helper.rb
59
+ - vendor/assets/javascripts/init.js
60
+ - vendor/assets/javascripts/jqmodal.js
61
+ - vendor/assets/stylesheets/jqmodal.css
62
+ homepage: http://www.smartapps.ru
63
+ licenses: []
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project: feedbackable
82
+ rubygems_version: 1.8.15
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: Add feedback to your models
86
+ test_files: []