Несовместим ли sprintf с sinatra?

#ruby #sinatra

#ruby #sinatra

Вопрос:

Скажем, у меня есть это:

 class Account
  ...
  property :charge, Decimal, :precision => 7, :scale => 2
  ...
  classy stuff
  ...

  def self.balance(prefix)
    x = Account.get(prefix.to_sym).order(:fields => [:charge]).sum(:charge)
    sprintf("%5.2f", x)
  end
end
  

(Редактировать: значение полей all :charge равно 0.13E2 (0.1E2 0.3E1). Это правильно возвращено. Только в представлении кажется, что он заблокирован sprintf )

В IRB Account.balance(:AAA) возвращает => "13.00"

если я вызываю Account.balance(:AAA) из представления, я получаю TypeError в /accounts не может преобразовать nil в Float

Account.balance(:AAA) работает везде, где я его вызываю, кроме как в представлении. Если я удалю sprintf("%5.2f", x) , я получу 0.13E2 представление. (использование Account.balance(:AAA).to_f в представлении дает мне 13.0 )

Несовместим ли sinatra с sprintf ? или я не понимаю, как использовать sprintf ?

(Редактировать: это оскорбительный вид:)

 <section>
  <% @accounts.each do |account| %>
    <article>
      <h2><%= account.prefix %></h2>
      <span><p>This account belongs to <%= account.name %> amp; has a balance of $<%= Account.balance(account.prefix) %>.</p></span>
    </article>
  <% end %>
</section> 
  

Комментарии:

1. Похоже x , что есть nil . Попробуйте и посмотрите, правильно ли это, а затем выясните, почему x nil ; трудно сказать из вставленного вами кода.

2. Казалось бы, так. Почему тогда IRB возвращает «правильный» результат, в то время как представление из sinatra возвращает ошибку?

3. Я не могу сказать; но проблема, похоже, не в этом sprintf . Посмотрите, можете ли вы добавить несколько отладочных инструкций, чтобы увидеть, что происходит. Что Account.get(prefix.to_sym) возвращает? и т.д…

4. prefix = 'AAA' Account.get(prefix.to_sym) возвращает правильную учетную <Account @id=3 @prefix="AAA" @name="Wanda" @balance=#<BigDecimal:7f94fc45e4b0,'0.0',9(18)> @user_login="wanda"> запись и Account.get(prefix.to_sym).orders.all возвращает все заказы. 0o

5. Продолжайте оттуда, что Account.get(prefix.to_sym).order(:fields => [:charge]) возвращает? И Account.get(prefix.to_sym).order(:fields => [:charge]).sum(:charge) ?

Ответ №1:

Не было бы более разумным определять balance как метод экземпляра, а не как метод класса? Из вашего примера похоже, что вы все равно вызываете balance account определенным образом, так почему бы не сделать это:

 # the model

class Account
  #...

  def balance
    amount = self.order(:fields => [:charge]).sum(:charge)
    sprintf "%5.2f", amount

    # or the infix version:
    "%5.2f" % amount
  end
end
  

,

 # the view

...balance of $<%= account.balance %>...
  

Я знаю, что это не решает sprintf само по себе, но проблема, скорее всего, исходит из слегка запутанного поиска, чем из встроенного метода. Даже если мой конкретный код не подходит для вашего приложения, возможно, стоит упростить этап поиска, даже если для этого потребуется еще несколько строк кода.

Преимущество этого подхода в том, что нет никаких сомнений в том, что вы получите правильную Account запись.

Комментарии:

1. Что-то, что нужно учитывать. Может измениться на что-то подобное в будущем. Тогда любая учетная запись вернет свое вычисленное значение из вызова balance . Но, увы, вы правы… это все еще не решает sprintf проблему. =(

2. Я надеялся, что если вы внесете это изменение, проблема будет устранена, поскольку я подозреваю, что это больше связано с x than sprintf . Что, если добавить временную строку отладки: p x ; sprintf("%5.2f", x) ? Если это показывает, что x это nil так, то я бы сказал, что мой ответ должен решить проблему, поскольку это просто ошибка в коде поиска или определении базы данных (вы уверены, что :prefix столбец никогда nil не бывает?)

3. Итак, когда я добавил вашу строку отладки, amp; и указал safari на соответствующий маршрут, он разбил safari и shotgun . Итак, я удалил весь класс, перепечатал его. и теперь мой метод и ваш работают отлично. Я понятия не имею, почему. Я только предполагаю, что что-то еще в классе было злым. Хотя мне все еще нужен мой метод класса (для других частей приложения, за которые я не несу ответственности, мне нравится ваш метод экземпляра. Поэтому я думаю, что я собираюсь его использовать. Большое спасибо за вашу помощь!

4. Рад, что это сработало. Также по опыту, хотя это не должно быть проблемой, я обнаружил, что shotgun иногда не перезапускается должным образом и переносит ошибки, которые были исправлены в исходном коде. Не помешает вручную завершить процесс и время от времени перезапускать shotgun, если возникнут проблемы.

5. Да, я тоже это обнаружил. Копая глубже, я думаю, что я действительно понял, что происходит. Я недавно обновился до Lion, у меня всего 2 ГБ оперативной памяти, открыты терминал, Safari, мой редактор и почта, у меня всего около ~ 14 МБ свободного места. Я думаю, что :charge то, что происходило, на самом деле является самим вычисляемым значением, и если какое-либо из значений, где nil один из методов :charge калькулятора будет продолжать пытаться получить значение BigDecimal… пока вся моя оперативная память не будет съедена, и это приведет к сбою.

Ответ №2:

протестировал его с помощью небольшого приложения sinatra, и оно сработало для меня

app.rb

 #!/usr/bin/env ruby

require 'rubygems'
require 'sinatra'

get '/' do
  @x = 10.23
  erb :index
end
  

просмотры/index.erb

 <%= sprintf("%5.2f", @x) %>
  

вывод:

 10.23
  

ruby 1.9.2 / sinatra 1.3.1

Я думаю, что перед sprintf есть еще одна ошибка из-за вашего сообщения об ошибке:

 can't convert nil into Float
  

похоже, ваш x равен нулю. постарайтесь убедиться, что x там не равно нулю, тогда sprintf должен работать должным образом.

Комментарии:

1. Я вижу, что в вашем примере вы назначаете x в представлении. Ваше приложение для быстрого тестирования также работает для меня. Мое приложение работает, если я назначаю x в представлении. Однако извлечение x из моей базы данных (datamapper) по-прежнему возвращает ту же ошибку. Я предполагаю, что это может быть ошибка datamapper, но извлечение from базы данных в IRB по-прежнему возвращает «правильный» результат, поэтому я бы предположил, что это означает, что какая-то вещь в том, как sinatra работает с представлением, не взаимодействует sprintf .

2. обновил мой ответ, и он все еще работает для меня. может быть, вы забыли @ для объявления x в качестве переменной экземпляра?

3. Этот небольшой фрагмент кода используется в представлении, в котором перечислены все учетные записи. в маршрут @accounts = Accounts.all определен. Затем в представлении <% @accounts.each do |account| %> я <article> получаю для каждой учетной записи. Тогда есть строка, которая (прямо сейчас) вызывает <%= Account . баланс (account.prefix) %> для печати баланса учетной записи (существует также вызываемый вспомогательный метод account_balance , который точно такой же, его использование в любом месте, кроме представления, дает «правильный» результат. Я перешел на Account.balance метод, когда начал отслеживать эту проблему)

4. Попробуйте изменить переменную в sprintf на что-нибудь тривиальное, чтобы посмотреть, работает ли это. Может быть, вы можете опубликовать код представления, чтобы я мог помочь больше

5. Похоже, проблема была где-то еще в приложении 0o в любом случае большое спасибо за вашу помощь!