RailsとFlexでリモートオブジェクト通信して遊ぶ覚え書き
WebORBを使ってRemoteObjectでデータのやり取りをするのに、勝手に遊んでる所を今のうちにまとめときます。
インストールは当初の覚え書きに。
セットアップできたら、railsでは app/services にクラスを追加していくことになるのですが、サービスを書くのにひな形が欲しくって、ふつうのscaffoldでは作れないのでオリジナルのを書く。
railsにオリジナルのscaffoldを追加するには、ホームディレクトリに .rails ディレクトリ を作成して、その中に入れると良いみたいです。(Windowsな人がどうすればいいのか分かりません・・・すみません)
具体的には、
.rails - generators - scaffold_weborb - template
というディレクトリを掘ります。(scaffold_weborbという名前の例です)
このgenerators以下はrailsのscaffoldのコードが書かれているファイルのところと同じ構成です。
例えばうちのMacだと
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/rails-1.2.6/lib/rails_generator/generators/components
てなところにソースがあるみたいなので、この内容をまねして作ります。
scaffold_weborb直下に
scaffold_weborb_generator.rb
class ScaffoldingSandbox include ActionView::Helpers::ActiveRecordHelper attr_accessor :form_action, :singular_name, :suffix, :model_instance def sandbox_binding binding end def default_input_block Proc.new { |record, column| " itm[:#{column.name}] = r[:#{column.name}]" } end end class ActionView::Helpers::InstanceTag def to_input_field_tag(field_type, options={}) field_meth = "#{field_type}_field" "<%= #{field_meth} '#{@object_name}', '#{@method_name}' #{options.empty? ? '' : ', '+options.inspect} %>" end def to_text_area_tag(options = {}) "<%= text_area '#{@object_name}', '#{@method_name}' #{options.empty? ? '' : ', '+ options.inspect} %>" end def to_date_select_tag(options = {}) "<%= date_select '#{@object_name}', '#{@method_name}' #{options.empty? ? '' : ', '+ options.inspect} %>" end def to_datetime_select_tag(options = {}) "<%= datetime_select '#{@object_name}', '#{@method_name}' #{options.empty? ? '' : ', '+ options.inspect} %>" end def to_time_select_tag(options = {}) "<%= time_select '#{@object_name}', '#{@method_name}' #{options.empty? ? '' : ', '+ options.inspect} %>" end end class ScaffoldWeborbGenerator < Rails::Generator::NamedBase attr_reader :controller_name, :controller_class_path, :controller_file_path, :controller_class_nesting, :controller_class_nesting_depth, :controller_class_name, :controller_singular_name, :controller_plural_name alias_method :controller_file_name, :controller_singular_name alias_method :controller_table_name, :controller_plural_name def initialize(runtime_args, runtime_options = {}) super # Take controller name from the next argument. Default to the pluralized model name. @controller_name = args.shift @controller_name ||= ActiveRecord::Base.pluralize_table_names ? @name.pluralize : @name base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name) @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name) if @controller_class_nesting.empty? @controller_class_name = @controller_class_name_without_nesting else @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}" end end def manifest record do |m| # Check for class naming collisions. m.class_collisions controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}ControllerTest", "#{controller_class_name}Helper" # Controller, helper, views, and test directories. m.directory File.join('app/services') m.directory File.join('app/views', controller_class_path, controller_file_name) m.directory File.join('test/functional', controller_class_path) # Depend on model generator but skip if the model exists. m.dependency 'model', [singular_name], :collision => :skip, :skip_migration => true # Service m.complex_template 'service.rb', File.join('app/services', "#{controller_class_name}Service.rb"), :insert => "service_scaffolding.rb", :sandbox => lambda { create_sandbox }, :begin_mark => 'rec', :end_mark => 'eorec', :mark_id => singular_name end end protected # Override with your own usage banner. def banner "Usage: #{$0} scaffold ModelName [ControllerName] [action, ...]" end def scaffold_views %w(list) end def scaffold_actions scaffold_views + %w(index create update destroy) end def model_name class_name.demodulize end def unscaffolded_actions args - scaffold_actions end def suffix "_#{singular_name}" if options[:suffix] end def create_sandbox sandbox = ScaffoldingSandbox.new sandbox.singular_name = singular_name begin sandbox.model_instance = model_instance sandbox.instance_variable_set("@#{singular_name}", sandbox.model_instance) rescue ActiveRecord::StatementInvalid => e logger.error "Before updating scaffolding from new DB schema, try creating a table for your model (#{class_name})" raise SystemExit end sandbox.suffix = suffix sandbox end def model_instance base = class_nesting.split('::').inject(Object) do |base, nested| break base.const_get(nested) if base.const_defined?(nested) base.const_set(nested, Module.new) end unless base.const_defined?(@class_name_without_nesting) base.const_set(@class_name_without_nesting, Class.new(ActiveRecord::Base)) end class_name.constantize.new end end
ってファイルを置いて
templatesの下に
service_scaffolding.rb
<%= all_input_tags(@model_instance, @singular_name, {}) %>
と
service.rb
class <%= controller_class_name %>Service def list<%= suffix %>(o) <%= model_name %>.find( :all , :order => "id asc").collect{|r| itm = {} itm[:id] = r[:id] <%= template_for_inclusion.gsub(/(\<\!\-\-)/,'#\1') %> itm } end def create<%= suffix %>(o) @<%= singular_name %> = <%= model_name %>.new(o) if @<%= singular_name %>.save @<%= singular_name %> else false end end def update(o) @<%= singular_name %> = <%= model_name %>.find(o['id']) if @<%= singular_name %>.update_attributes(o) @<%= singular_name %> else false end end def destroy<%= suffix %>(o) @<%= singular_name %> = <%= model_name %>.find(o['id']) if @<%= singular_name %>.destroy true else false end end end
を置きます。
※オリジナルのscaffoldから適当に手を加えたので、いらないコードとか混じってるかもしれません。
以上をしておくと、
ruby script/generate scaffold_weborb モデル
ってコマンドでapp/servicesにファイルができます。
開いて必要な変更をしたらremoting-config.xmlファイルに
<destination id="〜Service"> <properties> <source>〜Service</source> </properties> </destination>
のような記述を追加するのを忘れずに(で、httpdをrestart)
あと、scaffoldの機能追加ではついでにテーブルの表示と更新なら出来ちゃうようなMXMLを自動生成しておくと、Flexにファイルを持っていってコンパイルするだけでテーブル管理のアプリが出来るので、オリジナルのscaffoldと近い機能が提供できます。
# なんか、もうだれか作ってたりしませんかね。見つからずに自作してるわけですが。
・・・scaffoldの話だけになっちゃった。