힘껏 차라

TFYQA

Archive for the ‘ruby’ Category

ActiveRecord, ORA-01795

without comments

ActiveRecord 이용한 프로그램 짜던 중 안 풀리는 문제가 있어서 Ruby 포럼에 질문 올린 후 답변도 없고 당장 중요한 작업도 아니어서 제쳐놓고 있다가 간만에 다시 소스보다가 의외로 간단하게 해결해서 기록 남겨본다.

find 메서드의 조건으로 scala 객체가 넘겨지면 SQL 로 전환시 Where 절의 ‘=’ 구문으로, Collection 객체가 넘겨지면 ‘IN’ 구문으로 변환됩니다.
그런데 Collection 객체의 크기가 1,000이 넘으면 즉, ‘IN’ 조건에 들어갈 변수값이 1,000개가 넘으면 Oracle DB 의 경우 ‘OCIError: ORA-01795: maximum number of expressions in a list is 1000′ 란 에러가 납니다.

저같은 경우 선행해서 구한 ActiveRecord Collection 타입의 값을 직접 다음 find 메서드의 조건값으로 넘겨주려다 이 에러 만나서 질문할 때만 해도 먼저 얻었던 ActiveRecord Collection 객체를 일정 크기로 잘라서 어찌해볼까 하고 있었죠.

그런데 간만에 다시 들여다보니 의외로 쉬운 방법이 보이더군요.
1. ActiveRecord Collection 객체 때문에 고민하지말고 실제 ‘IN’ 조건에 쓰일 값만 사용하기위해 collect 메서드를 이용하여 필요값들만 Array 객체에 담는다.
2. max보다 큰 경우 max개씩 잘라서 find 메서드 실행하고 그렇게해서 얻어진 ActiveRecord Collection 값들을 concat 을 이용해서 합친다.
아래는 이렇게 구현된 샘플입니다.

def get_data(arr_list)
    find :all, :conditions => { :… => arr_list }
end

arr_list = pre_rs.collect {|row| row.col_name }

arr_size = arr_list.size
max_list = 1000.0

if arr_size <= max_list
    res = get_data(arr_list)
else
    res = Array.new
   1.step(ar_size, max_list) do |i|
        res = res.concat get_data(arr_list[i - 1, max_list])
   end
end

Written by tzara

February 26, 2009 at 11:20 am

Posted in ruby

Tagged with ,

Ruby Script 삽질

with 3 comments

작업을 단순화하려고 짰던 쉘스크립트(‘cygwin에서 expect 사용 시 에러 나는 경우‘)를 수정할 일이 생겼는데 이왕 고칠거 이 김에 Ruby 공부 겸해서 ruby 스크립트로 변경해 보기로 했다. 작업 흐름은 단순해서

  1. 업로드할 파일 목록을 적어 놓은 텍스트 파일을 읽어서
  2. 1에서 읽은 파일명들을 jar 로 묶어서
  3. 2에서 생성한 파일을 서버에 업로드하고
  4. 서버에 접속해서 몇가지 작업을 처리한다.

구현할 내용은 간단한데 Ruby 초짜다 보니 어쩔 수 없이 무한 삽질.

우선 File.open(…).readlines 에서의 문제

파일 읽은 내용을 jar 명령어의 실행 인자로 넘겨줘야 하는데 readlines 하면서 덧붙여지는 개행문자 때문에 실행 인자가 왜곡되는 현상 발생. 결국 line.chomp 식으로 처리해서 해결.

다음으로 외부 명령어 실행 문제.

jar 명령어를 실행시키기 위해 Ruby 매뉴얼 뒤져서 어렵사리 popen 을 이용해서 구현했다. 하지만 stdout 제어나 등등에서 부족한 점이 느껴져 다시 구글링해보니 popen4이 괜찮다 하길래 이걸 이용해보기로함 ( 참고 : ‘루비로 쉘 명령 내리는 방법 6가지‘ )

gem 이용해서 popen4 추가하고 테스트하는데 설치를 잘못했는지 아무리 해도 해당 라이브러리를 못찾아서 결국 포기하고 루비 표준 라이브러리에 포함되었다는 말만 믿고 popen3로 방향 선회.

popen3 를 이용해서 간단한 샘플 작성해서 테스트하는데 다음과 같은 에러가 또 난다.

`fork’: the fork() function is unimplemented on this machine (NotImplementedError)

알고 보니 popen3은 *NIX 계열에서만 사용 가능하단다. 윈도우 머쉰에서는 win32-open3를 사용해야 한다길래 win32-open3를 설치하고 샘플 코드 테스트. 다행히도 이건 예상보다 쉽게 성공.

파일 업로드 부분은 net/ftp 를 이용해서 쉽게 해결. 마지막으로 서버에 접속해서 명령 실행하기 위해 net/telnet 이용하는 부분이 남았는데

`waitfor’: timed out while waiting for more data (Timeout::Error)

라는 에러나면서 여기서 또 막힘.

‘waitfor’를 매뉴얼 등에서 찾아보니 명령어 입력을 위해 서버 프람프트를 인지시켜 줘야 되는 듯해서  Telnet.new의 인자로 ‘Prompt’ => />$/’와 같이 아주 간단한 패턴 매칭 구문 설정해줬더니 드디어 깔끔하게 실행된다.

아래는 꼬질하지만 이상의 삽질 끝에 만든 스크립트다. Ruby 조금만 다룰 줄 알아도 쉽게 개선할 부분 찾을 수 있을게다. 초짜를 위해 자유롭게 개선할 부분 지적해주길 부탁드린다.


#!/usr/bin/env ruby

require ‘net/ftp’
require ‘rubygems’
require “win32/open3″
require ‘net/telnet’

host_url = “….”
user_pw = “…”

target = ARGV[0]

BASE_CLASS_DIR=’d:/IDE/jdev_oaf/jdevhome/jdev/myclasses/’
Dir.chdir(BASE_CLASS_DIR)
$LOAD_PATH.unshift Dir.pwd

JAR_FILE = “test.jar”

if (File::exist?(JAR_FILE))
File.delete(JAR_FILE)
puts “Delete”
end

#uplist = File.open(“d:/work/oafup.lst”).readlines
uplist = File.open(‘d:/work/oafup.lst’, ‘r’){|file| file.readlines.collect{|line| line.chomp}}

#uplist = File.open(ARGV[0]).readlines
upfiles = “”

uplist.collect do | line |
upfiles += line.gsub(“.”, “\\”).gsub(/^/, “.\\”).concat(“.class “)
end

cmd = “jar cvMf #{JAR_FILE} #{upfiles}”

input, output, error = Open3.popen3(cmd)
err = error.gets # might be nil
if err
puts “Error running command ‘#{cmd}’: ” + err.chomp
next
end

out = output.readlines
puts out.to_s.strip

output.close
error.close

puts “to upload is done …”

if target == “2″
user_id=’…’
elsif target == “L”
user_id=’…’
end

REMOTE_BASE_DIR=”/#{user_id}/#{user_id}comn/java/”
puts REMOTE_BASE_DIR

ftp = Net::FTP.new(host_url)
ftp.login(user = user_id, passwd = user_pw)
ftp.chdir(REMOTE_BASE_DIR)
filesize = Float(File.size(JAR_FILE))
r_size = 0

ftp.putbinaryfile(JAR_FILE, File.basename(JAR_FILE)) { |data|
r_size += data.size
percent = (r_size/filesize)*100
printf(“Transfered : %i \r”, percent)

puts “Uploading a File to #{user_id} …”
}
ftp.close

tn = Net::Telnet.new(‘Host’ => host_url,
‘Prompt’ => />$/,
‘Telnetmode’ => true
) {|str| print str }
tn.login(user_id, user_pw) {|str| print str }
tn.cmd(“cd $JAVA_TOP”) {|str| print str }
tn.cmd(“jar tvf #{JAR_FILE}”) {|str| print str }
tn.cmd(“exit”) {|str| print str }
tn.close

puts “The test job is finished ….”

Written by tzara

March 19, 2008 at 4:19 pm

Posted in ruby

(J)Ruby on Rails 초보의 에러 해결 로그

without comments

1. Cygwin Rails issues “/dev/urandom” not found
Cygwin Rails issues “/dev/urandom” not found – Ruby on Rails: Talk | Google 그룹스

cygwin_install_dir\lib\ruby\gems\1.8\gems\rails-2.0.2\lib\rails_generatorsecret_key_generator.rb

def generate_secret_with_urandom
puts "Before Read" # <-- 추가
return File.read("/dev/urandom", 64).unpack("H*")[0]
end

ruby 1.8.6 릴리즈 후 Cygwin 변경이 되어서라는데 1.9.* 대에서는 수정되었다고 한다.

2. rails 업데이트 후 갑자기 ‘wrong number of arguments …’ 에러 발생

  • config/environment.rb 의 RAILS_GEM_VERSION 값을 현재 Rails 버전으로 변경
  • 간혹 나처럼 window 용 ruby, cygwin에 ruby, jruby 등이 같이 설치되어 있을 경우 각각 별도의 RubyGems를 사용하여 패키지가 설치/관리될 수 있으므로 각각의 RubyGems와 gem 으로 설치된 패키지들의 버전을 일치시켜 줄 필요있다 ( 안그러면 은근히 황당한 에러 만날 수 있다 ㅎ)

3. rails 1.* -> 2.* 업데이트 후 session 처리 관련 에러
’superkdk in the NET.’의 Rails2.0의 CookieStore 에 깔끔히 잘 정리되어있다.

요는 v1.* 와 v2.* 의 세션값 저장 처리 방식이 변경되었으므로 config/environment.rb 에 다음과 같은 식으로 세션의 secret 값을 넣어줘야 한다. ( 물론 rails 2.0 으로 프로젝트 생성하면 자동으로 이 secret 값 생성된다 )

config.action_controller.session = {
:session_key => '_my_app_session',
:secret => 'at_least_30_characters'
}

Powered by ScribeFire.

Written by tzara

January 9, 2008 at 10:36 am

Posted in ruby