Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 62adf584a50627a5556ce57ea86ab6f14f8b7444 0 parents
Roman Smirnov romul authored
10 .gitignore
@@ -0,0 +1,10 @@
+\#*
+*~
+.#*
+.DS_Store
+.idea
+.project
+tmp
+nbproject
+*.swp
+*.bak
23 LICENSE
@@ -0,0 +1,23 @@
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Rails Dog LLC nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13 README.md
@@ -0,0 +1,13 @@
+SpreeAddressBook
+================
+
+Introduction goes here.
+
+
+Example
+=======
+
+Example goes here.
+
+
+Copyright (c) 2011 [name of extension creator], released under the New BSD License
31 Rakefile
@@ -0,0 +1,31 @@
+require File.expand_path('../../config/application', __FILE__)
+
+require 'rubygems'
+require 'rake'
+require 'rake/testtask'
+require 'rake/packagetask'
+require 'rake/gempackagetask'
+
+spec = eval(File.read('spree_address_book.gemspec'))
+
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+end
+
+desc "Release to gemcutter"
+task :release => :package do
+ require 'rake/gemcutter'
+ Rake::Gemcutter::Tasks.new(spec).define
+ Rake::Task['gem:push'].invoke
+end
+
+desc "Default Task"
+task :default => [ :spec ]
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new
+
+# require 'cucumber/rake/task'
+# Cucumber::Rake::Task.new do |t|
+# t.cucumber_opts = %w{--format pretty}
+# end
12 app/controllers/addresses_controller.rb
@@ -0,0 +1,12 @@
+class AddressesController < Spree::BaseController
+ def destroy
+ @address = Address.find(params[:id])
+ if @address && @address.user == current_user
+ if @address.can_be_deleted?
+ @address.destroy
+ else
+ @address.update_attribute(:deleted_at, Time.now)
+ end
+ end
+ end
+end
55 app/controllers/checkout_controller_decorator.rb
@@ -0,0 +1,55 @@
+CheckoutController.class_eval do
+ after_filter :normalize_addresses, :only => :update
+ before_filter :set_addresses, :only => :update
+
+ protected
+
+ def set_addresses
+ return unless params[:order]
+
+ ship_address_id = params[:order].delete(:ship_address_id)
+ if ship_address_id.to_i > 0
+ params[:order].delete(:ship_address_attributes)
+ ship_address = Address.find(ship_address_id)
+ if ship_address && ship_address.user_id == current_user.try(:id)
+ @order.ship_address_id = ship_address.id
+ end
+ else
+ ship_address_id = params[:order][:ship_address_attributes][:id]
+ if ship_address_id
+ ship_address = Address.find(ship_address_id)
+ if ship_address && !ship_address.editable?
+ params[:order][:ship_address_attributes].delete(:id)
+ end
+ end
+ end
+
+ bill_address_id = params[:order].delete(:bill_address_id)
+ if bill_address_id.to_i > 0
+ params[:order].delete(:bill_address_attributes)
+ bill_address = Address.find(bill_address_id)
+ if bill_address && bill_address.user_id == current_user.try(:id)
+ @order.bill_address_id = bill_address.id
+ end
+ else
+ bill_address_id = params[:order][:bill_address_attributes][:id]
+ if bill_address_id
+ bill_address = Address.find(bill_address_id)
+ if bill_address && !bill_address.editable?
+ params[:order][:bill_address_attributes].delete(:id)
+ end
+ end
+ end
+ end
+
+ def normalize_addresses
+ return unless @order.bill_address_id
+ if @order.bill_address_id != @order.ship_address_id && @order.bill_address.same_as?(@order.ship_address)
+ @order.bill_address.destroy
+ @order.update_attribute(:bill_address_id, @order.ship_address_id)
+ else
+ @order.bill_address.update_attribute(:user_id, current_user.try(:id))
+ end
+ @order.ship_address.update_attribute(:user_id, current_user.try(:id))
+ end
+end
23 app/models/address_decorator.rb
@@ -0,0 +1,23 @@
+Address.class_eval do
+ belongs_to :user
+ before_update :check_address
+
+ # can modify an address if it's not been used in an order
+ def editable?
+ new_record? || (shipments.empty? && Order.complete.where("bill_address_id = ? OR ship_address_id = ?", self.id, self.id).count == 0)
+ end
+
+ def can_be_deleted?
+ shipments.empty? && Order.where("bill_address_id = ? OR ship_address_id = ?", self.id, self.id).count == 0
+ end
+
+ def to_s
+ "#{firstname} #{lastname}: #{address1} #{address2}"
+ end
+
+ private
+
+ def check_address
+ self.editable?
+ end
+end
8 app/models/order_decorator.rb
@@ -0,0 +1,8 @@
+Order.class_eval do
+ def clone_billing_address
+ if bill_address and self.ship_address.nil?
+ self.ship_address_id = bill_address.id
+ end
+ true
+ end
+end
3  app/models/user_decorator.rb
@@ -0,0 +1,3 @@
+User.class_eval do
+ has_many :addresses
+end
43 app/views/addresses/_form.html.erb
@@ -0,0 +1,43 @@
+<% ["firstname", "lastname", "address1", "address2", "city", "state", "zipcode", "country", "phone"].each do |field| %>
+ <p id="<%= [address_name, field].join('_') %>" class="field">
+ <%= address_form.label field, t(field, :scope => [:activerecord, :attributes, :address]) %>
+ <% if field == "country" %>
+ <span><%= address_form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %></span>
+ <span class="req">*</span>
+ <% elsif field == "state" && Spree::Config[:address_requires_state] %>
+ <span id="state">
+ <% have_states = !address.country.states.empty? %>
+ <noscript>
+ <%= address_form.text_field :state_name, :class => 'required' %>
+ </noscript>
+ <% state_elements = [
+ address_form.collection_select(:state_id, address.country.states,
+ :id, :name,
+ {:include_blank => true},
+ {:class => have_states ? "required" : "hidden",
+ :disabled => !have_states}) +
+ address_form.text_field(:state_name,
+ :class => !have_states ? "required" : "hidden",
+ :disabled => have_states)
+ ].join.gsub('"', "'").gsub("\n", "")
+ %>
+ <script type="text/javascript" language="javascript" charset="utf-8">
+ // <![CDATA[
+ document.write("<%= raw state_elements %>");
+ // ]]>
+ </script>
+ </span>
+ <span class="req">*</span>
+ <% elsif field == "address2" %>
+ <%= address_form.text_field field %>
+ <% else %>
+ <%= address_form.text_field field, :class => 'required' %><span class="req">*</span>
+ <% end %>
+ </p>
+<% end %>
+<% if Spree::Config["alternative_#{}_phone"] %>
+ <p id="altphone">
+ <%= address_form.label :alternative_phone, t(:alternative_phone) %>
+ <%= address_form.text_field :alternative_phone %>
+ </p>
+<% end %>
2  app/views/addresses/destroy.js.erb
@@ -0,0 +1,2 @@
+$("#billing_address_<%= @address.id %>").fadeOut();
+$("#shipping_address_<%= @address.id %>").fadeOut();
75 app/views/checkout/_address.html.erb
@@ -0,0 +1,75 @@
+<% @addresses = current_user ? current_user.addresses : [] %>
+<style>
+ div.inner input[type=text], div.inner select { width: 80%; }
+ .hidden { display: none; }
+ div#checkout #checkout_form_address #billing .select_address label { float:none; }
+ div#checkout #checkout_form_address #shipping .select_address label { float:none; }
+</style>
+
+<% ['billing', 'shipping'].each do |address_type| %>
+<% address_name = "#{address_type[0...4]}_address" %>
+<fieldset id="<%= address_type %>">
+ <legend><%= t(address_type + "_address")%></legend>
+ <div class="select_address">
+ <p class="field">
+ <% if @addresses.present? %>
+ <% @addresses.each do |address| %>
+ <span id="<%= [address_type, dom_id(address)].join('_') %>">
+ <label><%= form.radio_button "#{address_name}_id", address.id %> <%= address %></label> <%= link_to 'remove', address, :method => :delete, :remote => true %><br />
+ </span>
+ <% end %>
+ <label><%= form.radio_button "#{address_name}_id", 0 %> <%= ('other') %></label>
+ <% end %>
+ </p>
+ </div>
+ <%= form.fields_for address_name do |address_form| %>
+ <div class="inner">
+ <p class="field">&nbsp;</p>
+ <%= render :partial => 'addresses/form', :locals => {
+ :address_name => address_name,
+ :address_form => address_form,
+ :address => @order.send(address_name)
+ } %>
+ </div>
+ <% end %>
+</fieldset>
+<% end %>
+
+<hr class="space" />
+<div class="form-buttons">
+ <input type="submit" class="continue button primary" value="<%=t("save_and_continue") %>" />
+</div>
+<% if @addresses.present? %>
+ <%= javascript_tag do %>
+ $(document).ready(function(){
+ /*$(".inner input").attr('disabled', 'disabled');
+ $(".inner select").attr('disabled', 'disabled');
+ $(".inner").hide();*/
+
+ $("input[name='order[bill_address_id]']:radio").change(function(){
+ if ($("input[name='order[bill_address_id]']:checked").val() == '0') {
+ $("#billing .inner input").removeAttr('disabled');
+ $("#billing .inner select").removeAttr('disabled');
+ $("#billing .inner").fadeIn();
+ } else {
+ $("#billing .inner input").attr('disabled', 'disabled');
+ $("#billing .inner select").attr('disabled', 'disabled');
+ $("#billing .inner").fadeOut();
+ }
+ });
+
+ $("input[name='order[ship_address_id]']:radio").change(function(){
+ if ($("input[name='order[ship_address_id]']:checked").val() == '0') {
+ $("#shipping .inner input").removeAttr('disabled');
+ $("#shipping .inner select").removeAttr('disabled');
+ $("#shipping .inner").fadeIn();
+ } else {
+ $("#shipping .inner input").attr('disabled', 'disabled');
+ $("#shipping .inner select").attr('disabled', 'disabled');
+ $("#shipping .inner").fadeOut();
+ }
+ });
+
+ });
+ <% end %>
+<% end %>
3  config/routes.rb
@@ -0,0 +1,3 @@
+Rails.application.routes.draw do
+ resources :addresses, :only => [:edit, :update, :destroy]
+end
15 db/migrate/20110302102208_add_user_id_and_deleted_at_to_addresses.rb
@@ -0,0 +1,15 @@
+class AddUserIdAndDeletedAtToAddresses < ActiveRecord::Migration
+ def self.up
+ change_table :addresses do |t|
+ t.integer :user_id
+ t.datetime :deleted_at
+ end
+ end
+
+ def self.down
+ change_table :addresses do |t|
+ t.remove :deleted_at
+ t.remove :user_id
+ end
+ end
+end
17 lib/spree_address_book.rb
@@ -0,0 +1,17 @@
+require 'spree_core'
+require 'spree_address_book_hooks'
+
+module SpreeAddressBook
+ class Engine < Rails::Engine
+
+ config.autoload_paths += %W(#{config.root}/lib)
+
+ def self.activate
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
+ Rails.env.production? ? require(c) : load(c)
+ end
+ end
+
+ config.to_prepare &method(:activate).to_proc
+ end
+end
3  lib/spree_address_book_hooks.rb
@@ -0,0 +1,3 @@
+class SpreeAddressBookHooks < Spree::ThemeSupport::HookListener
+ # custom hooks go here
+end
25 lib/tasks/install.rake
@@ -0,0 +1,25 @@
+namespace :spree_address_book do
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
+ task :install do
+ Rake::Task['spree_address_book:install:migrations'].invoke
+ Rake::Task['spree_address_book:install:assets'].invoke
+ end
+
+ namespace :install do
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
+ task :migrations do
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
+ destination = File.join(Rails.root, 'db')
+ Spree::FileUtilz.mirror_files(source, destination)
+ end
+
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
+ task :assets do
+ source = File.join(File.dirname(__FILE__), '..', '..', 'public')
+ destination = File.join(Rails.root, 'public')
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
+ Spree::FileUtilz.mirror_files(source, destination)
+ end
+ end
+
+end
1  lib/tasks/spree_address_book.rake
@@ -0,0 +1 @@
+# add custom rake tasks here
30 spec/spec_helper.rb
@@ -0,0 +1,30 @@
+# This file is copied to ~/spec when you run 'ruby script/generate rspec'
+# from the project root directory.
+ENV["RAILS_ENV"] ||= 'test'
+require File.expand_path("../../../config/environment", __FILE__)
+require 'rspec/rails'
+
+# Requires supporting files with custom matchers and macros, etc,
+# in ./support/ and its subdirectories.
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
+
+RSpec.configure do |config|
+ # == Mock Framework
+ #
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
+ #
+ # config.mock_with :mocha
+ # config.mock_with :flexmock
+ # config.mock_with :rr
+ config.mock_with :rspec
+
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
+
+ #config.include Devise::TestHelpers, :type => :controller
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, comment the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+end
+
+@configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
21 spree_address_book.gemspec
@@ -0,0 +1,21 @@
+Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = 'spree_address_book'
+ s.version = '0.40.0'
+ s.summary = 'Add gem summary here'
+ #s.description = 'Add (optional) gem description here'
+ s.required_ruby_version = '>= 1.8.7'
+
+ # s.author = 'David Heinemeier Hansson'
+ # s.email = 'david@loudthinking.com'
+ # s.homepage = 'http://www.rubyonrails.org'
+ # s.rubyforge_project = 'actionmailer'
+
+ s.files = Dir['CHANGELOG', 'README.md', 'LICENSE', 'lib/**/*', 'app/**/*', 'db/**/*', 'public/**/*']
+ s.require_path = 'lib'
+ s.requirements << 'none'
+
+ s.has_rdoc = true
+
+ s.add_dependency('spree_core', '>= 0.40.0')
+end
Please sign in to comment.
Something went wrong with that request. Please try again.