Meadow設定

MeadowRubyを使いたいし、半透明にした〜い!

・インストール
http://www.meadowy.org/meadow/wiki/%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89
3.00のjaをゲット。パッケージは全てインストールした。

・半透明化
http://www.meadowy.org/meadow/wiki/%E8%A9%B3%E7%B4%B0%E8%A8%AD%E5%AE%9A%E5%8F%8A%E3%81%B3%E6%8B%A1%E5%BC%B5%E6%A9%9F%E8%83%BD
インストールの際に、.emacsの参照場所を、何もいじっていない。
その上で、C:\meadow\.emacsを自分で作成。あとは、コードを書いた


Rubyに対応
http://capsctrl.que.jp/kdmsnr/?Meadow#l18
miscを検索。あとは、これにのっている通り。


できた〜☆

あと、RHTMLとかにも対応させたいよね。
http://hp.vector.co.jp/authors/VA021626/pc/meadow.html#HTML

入力文章からの改行の反映

#in helper

  def h_with_br(text)
    safe_text = h(text) #一度サニタイズ
    safe_text.gsub(/\n/,"\n<br>")#\nはソース上でも改行するために
  end

※gsub!を使うと上手く行かないので注意。
gsub!はマッチしなかった時に、元の文字列でなくnilを返してしまうから。よって、
gsubを用いる。結構はまります。

添付ファイルを置く

■例えば、紹介のpdfファイルへのリンクを貼りたい


実際のパスには、app/controllerとか、publicとかは入らない。pub/user/**.csvにアクセス
するならhttp://DOMAIN/user/csv_up_format.csv


今が、app/views/administrator/student/csv_upload.rhtmlだとしたら<%= link_to "アップロードファイルの雛形","../../user/csv_up_format.csv" %> 
で、publicにあるCSVの雛形へのリンクを貼れる。

CSVUP

CSVにデータを入れ、アップすると、入れているデータに基づいて登録が行われる

#StudentController
  
  def upload
    
    begin
      @students,@at_recs = get_data_from_file(params[:file])
     
      if @students.empty?
        render_with_flash("csv_upload","CSVファイルが空か、指定されたファイルが存在しません")
           
      elsif (result = csv_datas_valid?(@students,@at_recs))[0]
     
        new_commer = 0
        for i in 0...@students.size
          unless @students[i].id
            @students[i].save 
            new_commer+=1
          end
          @students[i].attendance_records << @at_recs[i] 
        end
        
        flash[:notice] = "#{@students.size}件のアップロードが完了しました。新規:#{new_commer}件、更新:#{@students.size - new_commer}"
        redirect_to :action => "list"
      else
        render_with_flash("csv_upload",result[1])
      end
      return 
    rescue Exception => e
      render_with_flash("csv_upload","ファイルにエラーがあります。確認して、再度アップロードして下さい:#{e.message}")
    end
  end

  def get_data_from_file(data_stream)
    raise "ファイル形式がCSVではありません" unless data_stream.original_filename =~ /.*\.csv$/
    
    sts = []
    atrs = []
    while(line = data_stream.gets) do
        row = line.chomp.split(/,/)
        raise "1列のサイズは17でなければなりません" unless row.size == Student::CSV_UP_COL_SIZE
        
        student = Student.new_by_csv(row)
        at_rec = AttendanceRecord.new_by_csv(row)
        sts << student
        atrs << at_rec
    end
    return sts,atrs
  end
  
  def csv_datas_valid?(students,at_recs)
    return [false,"学生の数と、出欠データの数が一致していません"] unless students.size == at_recs.size
    
    invalid_lines = []
    for i in 0...students.size
      next if (students[i].valid? && at_recs[i].valid?) 
      invalid_lines << i+1
    end
    return [false,"#{invalid_lines.join(' , ')}行目のデータが不正です。確認して下さい"] unless invalid_lines.empty?
    return [true]
  end
#Student

def to_export_format(event_name)
   result = [ " "+ (event_name == "面接" ? 
                      (self.interview ? self.interview.held_date_time.strftime("%Y/%m/%d") : "") :
                       self.attendance_records.first.event_date.strftime("%Y/%m/%d")  
                    ),
               (event_name == "面接" ? "" : self.attendance_records.first.status.tosjis),
               (self.interview_type ? self.interview_type.name.tosjis : ""),
                self.student_status.name.tosjis,
                self.family_name.tosjis,
                self.first_name.tosjis,
                self.family_name_kana.tosjis,
                self.first_name_kana.tosjis,
                self.sex.tosjis,
                self.mail_address,
                to_mobile_format(self.mobile_phone_no),
              " "+self.birthday.strftime("%Y/%m/%d"),
                self.segment.tosjis,
                self.major.tosjis,
                self.grade,
                self.school.tosjis,
                self.department.tosjis,
                self.apply_channel.tosjis
            ]
    unless self.attendance_records.empty?
      at_rec = self.class.find_by_id(self.id).attendance_records
      return result+["",""] unless at_rec
      
      at_rec_ev_st = at_rec.map{|rec| [rec.event_name,rec.status]}
      result += [(at_rec_ev_st.include?(["説明会","参加"]) ? "".tosjis : "")]
      result += [(at_rec_ev_st.include?(["採裏セミナー","参加"]) ? "".tosjis : "")]
    else
      result += ["",""]
    end
      return result
  end


#AttendanceRecord

  def validate
    return unless self.event_date
    self.errors.add(:event_date,"が現在より先です") if self.event_date > Time.now
  
    unless (EVENT_NAMES.flatten.include?(self.event_name) || self.event_name =~ /面接/)
      self.errors.add(:event_name,"が選択肢にない値です")
    end
    
    unless ATTENDANCE_STATUSES.flatten.include?(self.status) 
      self.errors.add(:status,"が選択肢にない値です")
    end
    
  end

  def self.new_by_csv(row)
    attr ={ 
            :event_date => (row[0] =~ /^\d\d\d\d\/\d\d?\/\d\d?$/ ? Time.parse(row[0]) : ""),
            :event_name => (row[1] ? row[1].toutf8 : ""),
            :status => (row[2] ? row[2].toutf8 : "")
           }
    self.new(attr)
  end
#view

<% @title="CSV一括登録" -%>
  アップロードの雛形を使う場合、事前にヘルプを参照して下さい。<br><br>
  <% form_tag( {:action => "upload"},{ :multipart => true }) do -%>
  <p>アップロードファイル<br>
    <%= file_field_tag(:file) %>
  </p>
  <%= submit_tag("アップロード") %>
  <% end -%>
  <br>
  <%= link_to "戻る",:action => "list" %> 
  <%= link_to "アップロードファイルの雛形","../../user/csv_up_format.csv" %> 
  <%= link_to "一括登録のヘルプ",:action => "csv_upload_help" %>

既存のクラスを拡張してメソッドを持たせる

■テストの際にも使える(例:ファイルアップのテスト)


ファイルアップは、multipartフォームが用いられ、malutipart/form-dataで扱われるオブジェクト
は、StringIO(大きいとFileになる?)であり、かつ、以下の3つのメソを持っている。

                                                      • -

・local_path
・original_filename
・content_type

                                                      • -

しかし、テストでFileオブジェクトを生成して、
post :upload :file => File.open(filename)のようにやっても、例えば、コントローラの方で、
params[:file].original_filenameとかの操作を行っていたらならば、当然、UndefMethodエラー
となる。


これを防止するために、IOを持つFileクラスのオブジェクトに、上記の3つのメソッドを追加して、
あたかもmultipartで送られてきたデータのように振舞わせる。
今回は、original_filenameだけを持たせてみる。

 def upload_file(filename)
    t = File.open(filename,"r")
   
    (class << t; self; end).class_eval do
      define_method(:original_filename){File.basename(filename)}
    end
   
    return t
  end


このように、クラスのファイルに書くのではなく、オブジェクトを生成してから書いている。


※オリジナルはこれ
http://wiki.rubyonrails.org/rails/pages/HowtoUploadFiles
または、「はじめようRuby on Raiks」p116



これを使ったCSVUPのテストはこんな感じ

   def test_upload
    previous_count = Student.count
    post :upload,:file => upload_file(File.dirname(__FILE__) + '/../../upload_files/test_upload.csv')
    assert_redirected_to :action => "list"
    assert_equal 2,assigns(:students).size
    assert_equal assigns(:students).size,assigns(:at_recs).size
    assert_equal previous_count + 2,Student.count
  end
  
  def upload_invalid_test(filename)
    previous_count = Student.count
    post :upload,:file => upload_file(File.dirname(__FILE__) + '/../../upload_files/' + filename)
    assert_template "csv_upload"
    assert_equal previous_count ,Student.count
  end
  
  def test_invalid_upload_with_invalid_filetype
    upload_invalid_test('test_upload.xls')
  end
  
  def test_invalid_upload_with_over_linesized_file
    upload_invalid_test('test_overline_upload.csv')
  end

  def test_invalid_upload_with_invalid_params
    upload_invalid_test('test_invalid_upload.csv')
  end