배치 된 환경에서의 모델을 모델 환경에서의 모델도 개발 환경에서 얻는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/2214367

문제

Capistrano 및 Git과 결합 된 Ruby on Rails를 사용하여 성가신 문제가 발생합니다.

나는 다음과 같이 보이는 색인 조치가 포함 된 컨트롤러 "사람"이 있습니다.

def index
  @people = Person.find( :conditions => params[:search] )
end

사람 테이블에는 부울 "is_admin"열이 있습니다. 일부 사람들이 관리자이고 일부는 아니라고 가정하면 http : // localhost : 3000/people? 검색 [is_admin] = true 채워야합니다 @사람들 일부 사용자와 함께 ... 앱을 실행할 때 이것은 내 로컬 PC에 해당됩니다. 개발 방법..

하지만 .... 내 서버 계정 (Railsplayground)에 배포 할 때 http://mydomain.com/people?seargue?search@is_admin ]=true 일치하는 항목을 찾지 못합니다. 그러나 내가 변하면 ...? 검색 [is_admin] = true 에게 ...? 검색 [is_admin] = 1 응답은 예상대로 관리자 사용자를 반환합니다 ...

로컬 PC로 돌아와서 "true"대신 "1"을 사용하면 실패합니다.

결론은 그 것입니다

Person.find( :all, :conditions => { :is_admin => 'true' } )

내 개발 환경에서 작동합니다

Person.find( :all, :conditions => { :is_admin => 1 } )

내 배포 된 환경에서 작동합니다.

왜 이런거야? 그리고 어떻게 고칠 수 있습니까?

이상적으로는 다음과 같은 링크를 배치하고 싶습니다.

link_to( "Administrators", {
  :controller => '/people',
  :action => :index,
  :search => { :is_admin => true }
})

관리자 목록을 받으십시오 :).

내 개발 데이터베이스는 SQLITE3 파일이고 프로덕션은 MySQL 데이터베이스입니다 ...

편집 : 나는 사용자 입력에 대한 이의 제기를 이해하지만이 예외적 인 경우 매우 사소한 위협입니다. 또한 내 현재 코드는 개발 PC 또는 제작 계정에서 완벽하게 작동하지만 두 가지 모두에서는 완벽하게 작동합니다. 가장 쉬운 Sollution은 sqlite3이 절약하고 Interperets 부울 가치를 바꾸는 방식을 바꾸는 것처럼 보이기 때문에 "Sqlite가 부울 가치를 절약하는 방식을 어떻게 바꾸는가?" 완벽하게 필요합니다 ...

도움이 되었습니까?

해결책

문제는 부울 값을 문자열로 전달하고 최종 동작은 활성 데이터베이스에 따라 다르다는 것입니다. 더 자세한 설명이 있습니다.

당신이 읽을 때 params[:search] 변수, 내용은 문자열이며 유형이 없습니다. 쿼리 문자열이 여부를 이해할 수 없기 때문입니다

params[:search][:is_admin] = "true"

실제로 의미합니다

params[:search][:is_admin] = "true"
params[:search][:is_admin] = true

마찬가지로, 당신이 1을 통과하면 당신은 끝납니다.

params[:search][:is_admin] = "1"

어느 것과 다릅니다

params[:search][:is_admin] = 1

부울을 전달하지 않기 때문에 값을 쿼리로 전달할 때 값은 데이터베이스 어댑터로 변환되지 않습니다. 최종 쿼리는 같은 결과를 얻습니다

SELECT * FROM `persons` WHERE `persons.is_admin` = 'true'

SQLITE3는 부울을 T/F 현으로 저장합니다. true 저장됩니다 't' 그리고 false 저장됩니다 'f'. 또한 True/False를 이해하고 자동으로 귀하의 쿼리를 번역합니다. 반대로 MySQL은 0/1과 true/false 만 이해하고 실패합니다.

동작을 전환 할 때 통과하십시오 1 대신에 true, 당신은 sqlite가 줄을 번역 할 수 없기 때문에 실패하게합니다. "1" 에게 't'. 반대로 MySQL은 할 수 있습니다.

두 경우 모두 잘못하고 있습니다. 문자열이 아니라 부울 가치를 전달해야합니다. 또한 사용자 입력을 신뢰해서는 안됩니다.

내 제안은 당신을 정상화하는 것입니다 params[:search] 먹이기 전에 Person.find.

다른 팁

SQLITE와 MYSQL 사용의 차이가 문제의 원인이라고 생각합니다.

그러나 쿼리 문자열에서 직접 통과 할 수있는 활성 레코드를 허용하는 것은 나에게 나쁜 생각처럼 보이며 앱을 SQL 주입 공격에 열어 둘 수 있습니다.

@Simone 답변은 왜 그런 행동을하는지 설명합니다. SQLITE3 및 MYSQL 모두에서 올바른 결과를 얻으려면 다음을 통과해야합니다.

Person.find( :all, :conditions => { :is_admin => true } )

한 수준의 매개 변수 만있는 경우 ( params[:search][:something] 그러나 더 깊은 것은 없습니다) 당신은 다음과 같은 조건으로 올바른 해시를 만들 수 있습니다.

my_conditions = Hash.new
params[:search].each do |item, value|
  my_conditions[item.to_sym] = value == 'true' ? true : value == 'false' ? false : value
end

그것은 모든 검색 매개 변수를 반복하고 모든 것을 변경합니다. 'true' 에게 true 그리고 'false' 에게 false. 다른 값이 있으면 그대로 남겨 둘 것입니다. 물론 원하는 논리를 여기에 넣을 수 있습니다. 다시 작성할 수있는 것보다 더 복잡해지면 if 또는 함께 switch.

당신이 할 수있는 것보다 :

Person.all(:conditions => my_conditions)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top