#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
возвращает все заказы. 0o5. Продолжайте оттуда, что
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
thansprintf
. Что, если добавить временную строку отладки: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 в любом случае большое спасибо за вашу помощь!