Created
September 25, 2013 13:24
-
-
Save svoboda-jan/6699529 to your computer and use it in GitHub Desktop.
Rails code sample with CouchDB database, INI config files and custom email validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# rails initializer to load *.ini into Rails.application.config | |
Dir.glob(File.join Rails.root, "/config/**/*.ini").each do |file_name| | |
config_name = File.basename(file_name, ".ini") | |
Rails.application.config.send "#{config_name}=", IniFile.new(file_name).to_struct.send(Rails.env) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'resolv' | |
require 'mail' | |
class EmailValidator < ActiveModel::EachValidator | |
def validate_each(record, attribute, value) | |
email = Mail::Address.new(value) rescue nil | |
return invalid(record, attribute) unless email.present? | |
# verify domain and parsed email address | |
return invalid(record, attribute) unless email.domain.present? and email.address == value | |
# valid domain must have at least two dot_atom_text elements (domainname.tld) | |
domain_tree = email.send :tree # mail gem does not expose the tree method | |
return invalid(record, attribute) unless domain_tree.domain.dot_atom_text.elements.size >= 2 | |
# check if the email domain has MX records | |
Resolv::DNS.open do |dns| | |
mx_records = dns.getresources(email.domain, Resolv::DNS::Resource::IN::MX) | |
return invalid(record, attribute) unless mx_records.present? | |
end | |
end | |
private | |
def invalid(record, attribute) | |
record.errors[attribute] << I18n.t('errors.messages.invalid') | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'ostruct' | |
require 'stringio' | |
class IniFile | |
def initialize(stream_or_path) | |
@options = {} | |
if stream_or_path.respond_to? :read | |
read_from_stream(stream_or_path) | |
else | |
read_from_stream(StringIO.new(File.read(stream_or_path))) | |
end | |
end | |
def to_hash | |
@options | |
end | |
alias_method :to_h, :to_hash | |
def to_struct | |
struct = OpenStruct.new | |
@options.each do |section,values| | |
struct.send("#{section}=", OpenStruct.new(values)) | |
end | |
struct | |
end | |
private | |
def read_from_stream(stream) | |
section = :general | |
while l = stream.gets | |
l.strip! | |
next if l.start_with? "#" or l.start_with? ";" | |
if l.start_with? "[" and l.end_with? "]" | |
section = l[1..-2].to_sym | |
@options[section] ||= {} | |
else | |
key, val = l.split("=", 2) | |
next if key.nil? or val.nil? | |
key = key.strip.to_sym | |
val.strip! | |
if @options[section].has_key?(key) | |
unless @options[section][key].is_a?(Array) | |
@options[section][key] = [@options[section][key]] | |
end | |
@options[section][key] << val | |
else | |
@options[section][key] = val | |
end | |
end | |
end | |
end | |
end | |
if __FILE__ == $0 | |
require 'test/unit' | |
require 'stringio' | |
INI_FILE = <<-INI | |
[example.com] | |
url=http://localhost:3000 | |
[cluster.example.com] | |
url=http://localhost:3000 | |
url=http://localhost:3001 | |
url=http://localhost:3002 | |
INI | |
class TestIniFile < Test::Unit::TestCase | |
def setup | |
@ini_file = IniFile.new(StringIO.new(INI_FILE)) | |
@hash = @ini_file.to_h | |
end | |
def test_parsing_sections_to_hash_keys | |
assert_equal [:"example.com", :"cluster.example.com"], @hash.keys | |
end | |
def test_parsing_sections_to_hash_values | |
assert_equal [ | |
{:url=>"http://localhost:3000"}, | |
{:url=>["http://localhost:3000", "http://localhost:3001", "http://localhost:3002"]} | |
], @hash.values | |
end | |
def test_parsing_multiple_values_to_array | |
assert_equal [ | |
"http://localhost:3000", | |
"http://localhost:3001", | |
"http://localhost:3002" | |
], @hash[:"cluster.example.com"][:url] | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class InventoryCard < CouchRest::Model::Base | |
include TenantModel | |
include ActiveModel::SerializerSupport | |
include TranslatedModel | |
include TranslatedParameterizedName | |
belongs_to :warehouse, :class_name => "Warehouse", :foreign_key => "warehouse_id" | |
belongs_to :supplier, :class_name => "Supplier", :foreign_key => "supplier_id" | |
belongs_to :vat_rate, :class_name => "VatRate", :foreign_key => "vat_rate_id" | |
collection_of :categories | |
property :sku, String | |
translates :name | |
translates :parameterized_name | |
translates :description | |
property :active, TrueClass, :default => true | |
# | |
# ... other property declarations ... | |
# | |
timestamps! | |
design do | |
view :by_tenant_id_and_locale_and_parameterized_name, { | |
:map => " | |
function(doc) { | |
if (doc['type'] == 'InventoryCard' && doc.name_translations && doc.active) { | |
for(locale in doc.name_translations) { | |
emit([ | |
doc.tenant_id, | |
locale, | |
doc.parameterized_name_translations[locale] | |
], 1) | |
} | |
} | |
} | |
", | |
:reduce => " | |
function(keys, values, rereduce) { | |
return sum(values); | |
} | |
" | |
} | |
# ... other view declarations ... | |
end | |
alias_method :to_param, :parameterized_name | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Api::V1::InventoryCardsController < Api::V1::BaseController | |
before_action :find_resource, :only => %w{ show update destroy upload_image destroy_image } | |
# sets HTTP headers for current page, per page and count and also @per_page var | |
set_pagination_headers :inventory_cards, 10, :only => %w{ index } | |
def index | |
@inventory_cards = current_tenant.inventory_cards | |
.page(params[:page]).per(@per_page) | |
respond_with @inventory_cards.to_a | |
end | |
def show | |
respond_with @inventory_card | |
end | |
def create | |
@inventory_card = InventoryCard.create( | |
params[:inventory_card].merge(:user_id => current_user.id, :id => nil) | |
) | |
respond_with @inventory_card | |
end | |
def update | |
@inventory_card.update_attributes params[:inventory_card] | |
respond_with @inventory_card | |
end | |
def destroy | |
respond_with @inventory_card.destroy | |
end | |
def upload_image | |
@inventory_card.add_image(params[:image].tempfile) | |
respond_with @inventory_card.images | |
end | |
def destroy_image | |
@inventory_card.delete_image(params[:file_name]) | |
respond_with @inventory_card.images | |
end | |
private | |
def find_resource | |
@inventory_card = InventoryCard.secure_find!(params[:id]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment