Modelde görünüm yerine "number_to_currency" yardımcı yöntemi nasıl kullanılır?


94

Modelimde şu şekilde to_dollaryöntem kullanmak istiyorum:

module JobsHelper      
  def to_dollar(amount)
    if amount < 0
      number_to_currency(amount.abs, :precision => 0, :format => "-%u%n")
    else
      number_to_currency(amount, :precision => 0)
    end
  end      
end

class Job < ActiveRecord::Base
  include JobsHelper
  def details
    return "Only " + to_dollar(part_amount_received) + 
           " out of " + to_dollar(price) + " received."
  end
end

Maalesef number_to_currencyyöntem burada tanınmıyor:

# <İş: 0x311eb00> için tanımlanmamış yöntem `` sayı_dan_kullanıma

Nasıl çalıştırılacağına dair bir fikrin var mı?

Yanıtlar:


104

Kullanılamaz çünkü bir modelde kullanımı (tipik olarak) MVC'yi ihlal eder (ve sizin durumunuzda öyle görünüyor). Verileri alıyorsunuz ve sunum için değiştiriyorsunuz. Bu, tanımı gereği, modele değil, görünüme aittir.

İşte bazı çözümler:

  • Model ve görünüm arasında uzlaşmak için bir sunum yapan kişi veya model görünümü nesnesi kullanın. Bu neredeyse kesinlikle diğer çözümlerden daha fazla ilk çalışma gerektirir, ancak neredeyse her zaman daha iyi bir tasarımdır. Bir sunum / görünüm modelinde yardımcıların kullanılması, geleneksel özel Rails yardımcılarının ve mantık dolu görünümlerin yerini alarak, görünüm katmanında yer aldıklarından MVC'yi ihlal etmez.

  • Açıkça include ActionView::Helpers::NumberHelperiçinde JobsHelperyerine Raylar bağlı olarak sihirli sizin için yüklü olması. Modelden bir yardımcıya erişmemeniz gerektiği için bu hala harika değil.

  • MVC ve SRP'yi ihlal edin . Bunun nasıl yapılacağı konusunda fguillen'in cevabına bakın . Burada yinelemeyeceğim çünkü buna katılmıyorum. Dahası, Sam'in cevabında olduğu gibi, modelinizi sunum yöntemleriyle kirletmeye katılmıyorum .

"Ama benim modelime to_csv& to_pdfyöntemlerimi yazmak için buna gerçekten ihtiyacım var !" Diye düşünüyorsanız , tüm önermeniz yanlıştır - sonuçta, bir to_htmlyönteminiz yok, değil mi? Yine de nesneniz genellikle HTML olarak işlenir. Veri modelinizin bir CSV'nin ne olduğunu bilmesini sağlamak yerine, çıktınızı oluşturmak için yeni bir sınıf oluşturmayı düşünün ( çünkü ).

Modeldeki ActiveModel doğrulama hataları için yardımcıları kullanmaya gelince, peki, üzgünüm ama ActiveModel / Rails, bir hatanın anlamsal fikrini geri döndürmek yerine, veri katmanında hata mesajlarını gerçekleştirmeye zorlayarak hepimizi mahvetti . daha sonra fark etti - çek . Bunu aşabilirsiniz, ancak temelde artık ActiveModel :: Errors kullanmamak anlamına gelir. Ben yaptım, iyi çalışıyor.

Bir kenara, aşağıda, yöntem kümesini kirletmeden bir sunucu / görünüm modeline yardımcıları dahil etmenin yararlı bir yolu var (çünkü örneğin yapabilmek MyPresenterOrViewModel.new.link_to(...)mantıklı değil):

class MyPresenterOrViewModel
  def some_field
    helper.number_to_currency(amount, :precision => 0)
  end

  private

  def helper
    @helper ||= Class.new do
      include ActionView::Helpers::NumberHelper
    end.new
  end
end

5
Genellikle bu kuralı izlerim, ancak modelde tanımlanan bir doğrulama hata mesajını biçimlendirmek için bir görüntüleme yardımcısına ihtiyacım olduğunda onu bozarım.
Florent2

44
Bu iyi bir tavsiye, ancak soruyu çözmediği için kötü bir cevap.
Jaryl

21
Bunun harika bir cevap olmadığı durumlar vardır, örneğin şu anda bir csv raporu oluşturuyorum ve böyle bir şeyi asla bir görünüm görmeyecek bir sınıfta to_csv yönteminde kullanmam gerekiyor. Sadece programlama ideallerini filizlemek her zaman yardımcı olmaz.
nitecoder

1
Evet, nitecoder ne dedi. Ben de aynı sorunla karşılaşıyorum. PDF raporları oluşturuyorum ve bir telefon numarasını güzel bir şekilde biçimlendirmek istiyorum.
James Adam

3
@maurice "Peki sadece bu tek şey" den şişirilmiş bir modele doğru kaygan bir eğim. Rails'teki uygulama yardımcıları önemsiz bir çekmecedir, sunum yapanların / görünüm modellerinin yönetilmesi daha kolaydır. Bir rapor için veri oluşturmayı ve bu verilerin (html | pdf | csv | vb.) Görünümünü oluşturmayı tek bir sorumluluk olarak görmüyorum, örneğin bir kişi ve bir HTML kişi göster sayfası için yaptığımdan daha fazla.
Andrew Marshall

184

Bu MVC deseni kırma olabilir ama bir desen kırmak için nedenler Bunları gerekli benim durumumda, her zaman olduğu hepiniz katılıyorum yöntemlere biçimlendirici para için bir şablon filtresinde bunları kullanmak ( Likit benim durumumda).

Sonunda, aşağıdaki gibi şeyler kullanarak bu para birimi biçimlendirme yöntemlerine erişebileceğimi öğrendim :

ActionController::Base.helpers.number_to_currency

6
Bu iyi, ancak bunu yapmanın biraz daha temiz bir yolu var. Bkz http://railscasts.com/episodes/132-helpers-outside-views
user664833

4
RailsCasts'te Yay yorum parçası: 2013'te Rails 3'te, bir Denetleyicide bir Görünüm yardımcısı kullanmak, view_context.number_to_currency (amount)
olleolleolle

3
"Para" mücevherini kullanmayı düşündünüz mü? Money nesnesi bir format () yöntemi sağladığından, bunu modelde, denetleyicide veya görünümde çağırabilirsiniz.
Zack Xu

74

Bu iş parçacığının çok eski olduğunu biliyorum, ancak birisi bu soruna Rails 4+ ile çözüm arayabilir. Geliştiriciler, aşağıdakileri kullanarak ilgili modülleri / sınıfları görüntülemeye erişmeden kullanılabilen ActiveSupport :: NumberHelper'ı ekledi:

ActiveSupport::NumberHelper.number_to_currency(amount, precision: 0)

number_to_percentageRails konsolundaki davranışını denemek istediğimde bu yaklaşım benim için çalıştı . Teşekkürler!
Jon Schneider

28

ActionView :: Helpers :: NumberHelper'ı da eklemeniz gerekir.

class Job < ActiveRecord::Base
  include ActionView::Helpers::NumberHelper
  include JobsHelper
  def details
    return "Only " + to_dollar(part_amount_received) + 
           " out of " + to_dollar(price) + " received."
  end
end

2
Teşekkürler, iyi görünüyor, ancak MVC'yi ihlal ettiğimi söyleyen diğerleriyle aynı fikirde olmalıyım. Ben detailsyardımcıyı koyacağım .
Misha Moroshko

1
Florent2 gibiyseniz ve bunu bir doğrulama mesajının parçası olarak koymanız gerekiyorsa faydalıdır. Teşekkürler Sam.
RyanJM

Bu benim için çalıştı. Bu prensibi ihlal eden bir çözüm, ona bağlı olandan açıkça daha iyi ise, MVC'yi (veya herhangi bir prensibi) her zaman takip etmenin mantıklı olduğunu düşünmüyorum.
Jason Swett

2
Bu yaklaşım tavsiye edilmez. İhtiyaç duymadığınız birçok yöntem ekler ve ad alanınızı karıştırır, bazı yöntemlerin üzerine yazabilir ve bazı yardımcı modüller diğer yardımcı modüllere güvenir (bu nedenle birden fazla modül eklemeniz gerekebilir), bu nedenle sorunu çözer daha da kötüsü. Açıklama ve daha iyi bir yaklaşım için bkz: http://railscasts.com/episodes/132-helpers-outside-views
user664833

6

@fguillenYanıtını geri alarak, modülümdeki number_to_currencyyöntemi geçersiz kılmak istedim, ApplicationHelperböylece değer olsaydı 0veya blankbunun yerine bir tire çıkardı.

İşte böyle bir şeyi faydalı bulmanız ihtimaline karşı benim kodum:

module ApplicationHelper
  def number_to_currency(value)
    if value == 0 or value.blank?
      raw "&ndash;"
    else
      ActionController::Base.helpers.number_to_currency(value)
    end
  end
end

4

Sen kullanabilirsiniz view_context.number_to_currencykontrolör veya modele doğrudan sizden.


3

@ fguillen'in yöntemi iyi, ancak burada biraz daha temiz bir yaklaşım var, özellikle sorunun iki referans yaptığı göz önüne alındığında to_dollar. İlk olarak Ryan Bates'in kodunu kullanarak göstereceğim ( http://railscasts.com/episodes/132-helpers-outside-views ).

def description
  "This category has #{helpers.pluralize(products.count, 'product')}."
end

def helpers
  ActionController::Base.helpers
end

Aramaya dikkat edin helpers.pluralize. Bu, def helpersbasitçe dönen yöntem tanımı ( ) nedeniyle mümkündür ActionController::Base.helpers. Bu nedenle helpers.pluralizekısaltmasıdır ActionController::Base.helpers.pluralize. Artık helpers.pluralizeuzun modül yollarını tekrar etmeden birden çok kez kullanabilirsiniz .

Sanırım bu özel sorunun cevabı şöyle olabilir:

class Job < ActiveRecord::Base
  include JobsHelper
  def details
    return "Only " + helpers.to_dollar(part_amount_received) + 
           " out of " + helpers.to_dollar(price) + " received."
  end

  def helpers
    ActionView::Helpers::NumberHelper
  end
end

2

İyi bir uygulama değil ama benim için işe yarıyor!

içe aktarmak için denetleyiciye ActionView :: Helpers :: NumberHelper ekleyin. Örneğin:

class ProveedorController < ApplicationController
    include ActionView::Helpers::NumberHelper
    # layout 'example'

    # GET /proveedores/filtro
    # GET /proveedores/filtro.json
    def filtro
        @proveedores = Proveedor.all

        respond_to do |format|
            format.html # filtro.html.erb
            format.json { render json: @proveedores }
        end
    end

    def valuacion_cartera
        @total_valuacion = 0
        facturas.each { |fac|
            @total_valuacion = @total_valuacion + fac.SumaDeImporte
        }

        @total = number_to_currency(@total_valuacion, :unit => "$ ")

        p '*'*80
        p @total_valuacion
    end
end

Umarım size yardımcı olur!


2

Bir Dekoratör kullanmaktan hiç kimsenin bahsetmemesi gerçekten şaşırttı. Amaçları, karşılaştığınız sorunu ve daha fazlasını çözmektir.

https://github.com/drapergem/draper

DÜZENLEME: Kabul edilen yanıt temelde böyle bir şey yapmayı öneriyor gibi görünüyor. Ama evet, dekoratör kullanmak istiyorsun. İşte daha fazlasını anlamanıza yardımcı olacak harika bir eğitim dizisi:

https://gorails.com/episodes/decorators-from-scratch?autoplay=1

PS - @ excid3 Ücretsiz üyelik aylarını kabul ediyorum LOL



-5

Yardımcı yöntemler genellikle Dosyaları görüntülemek için kullanılır. Bu yöntemlerin Model sınıfında kullanılması iyi bir uygulama değildir. Ama kullanmak istiyorsan, Sam'in cevabı tamam. VEYA kendi özel yönteminizi yazmanızı öneririm.


2
Bu bir cevap değil.
Bonifacio2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.