2011-03-03 22 views
71

Tôi muốn sử dụng to_dollar phương pháp trong mô hình của tôi như thế này:Cách sử dụng phương thức trợ giúp "number_to_currency" trong mô hình thay vì xem?

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 

Thật không may, phương pháp number_to_currency không được công nhận ở đây:

không xác định phương pháp 'number_to_currency' cho # < công việc: 0x311eb00>

Bất kỳ ý tưởng nào làm cho nó hoạt động?

Trả lời

76

Nó không có sẵn vì việc sử dụng nó trong một mô hình (thường) vi phạm MVC (và nó dường như trong trường hợp của bạn). Bạn đang lấy dữ liệu và thao tác nó để trình bày. Điều này, theo định nghĩa, thuộc về chế độ xem, không phải là mô hình.

Dưới đây là một số giải pháp:

  • Sử dụng một chương trình hoặc xem mô hình đối tượng làm trung gian giữa mô hình và xem. Điều này gần như chắc chắn đòi hỏi công việc ban đầu hơn các giải pháp khác, nhưng hầu như luôn luôn là một thiết kế tốt hơn. Việc sử dụng người trợ giúp trong người trình bày/chế độ xem không vi phạm MVC, vì họ cư trú trong lớp chế độ xem, thay thế người trợ giúp Rails tùy chỉnh truyền thống và chế độ xem được lấp đầy logic.

  • Rõ ràng include ActionView::Helpers::NumberHelper trong JobsHelper thay vì tùy thuộc vào Rails đã tải nó một cách kỳ diệu cho bạn. Điều này vẫn không tuyệt vời vì bạn không nên truy cập trình trợ giúp từ mô hình.

  • Vi phạm MVC & SRP. Xem fguillen’s answer để biết cách thực hiện việc này. Tôi sẽ không lặp lại ở đây vì tôi không đồng ý với điều đó. Mặc dù vậy, tôi không đồng ý với việc làm ô nhiễm mô hình của bạn bằng các phương thức trình bày như trong Sam’s answer.

Nếu bạn nghĩ rằng “nhưng tôi thực sự cần điều này để viết to_csv & to_pdf phương pháp của tôi trong mô hình của tôi!”, Sau đó toàn bộ tiền đề của bạn là sai sau khi tất cả, bạn không có một phương pháp to_html, làm bạn ? Nhưng đối tượng của bạn thường được hiển thị dưới dạng HTML. Xem xét việc tạo một lớp mới để tạo đầu ra của bạn thay vì làm cho mô hình dữ liệu của bạn biết CSV là gì (because it shouldn’t).

Đối với việc sử dụng trình trợ giúp cho lỗi xác thực ActiveModel trong mô hình, tốt, tôi xin lỗi nhưng ActiveModel/Rails đã làm hỏng tất cả chúng ta bằng cách buộc thông báo lỗi được thực hiện trong lớp dữ liệu, thay vì trả về ý tưởng ngữ nghĩa lỗi sẽ được nhận ra sau— tiếng thở dài. Bạn có thể giải quyết vấn đề này, nhưng về cơ bản có nghĩa là không còn sử dụng ActiveModel :: Errors nữa. Tôi đã thực hiện nó, nó hoạt động tốt. Ngoài ra, đây là một cách hữu ích để bao gồm những người trợ giúp trong một người trình bày/mô hình xem mà không gây ô nhiễm tập hợp các phương pháp của nó (vì có thể thực hiện được ví dụ như vậy, ví dụ:MyPresenterOrViewModel.new.link_to(...) không có ý nghĩa):

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 
+3

Tôi thường thực hiện theo quy tắc này nhưng ngắt nó khi tôi cần trình trợ giúp xem để định dạng thông báo lỗi xác thực được xác định trong mô hình. – Florent2

+0

Bộ sưu tập Rails chọn những người trợ giúp không tôn trọng MVC vì họ muốn thực hiện một phương thức mẫu trên mục có thể chọn để xác định nội dung hiển thị. Vì vậy, trong trường hợp đó bạn có thể hack xung quanh khuôn khổ hoặc vi phạm MVC. – Tony

+34

Đây là lời khuyên tốt, nhưng đó là một câu trả lời không tốt vì nó không giải quyết được câu hỏi. – Jaryl

25

Bạn cần phải cũng bao gồm các ActionView :: Helpers :: NumberHelper

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

Cảm ơn, có vẻ tốt, nhưng tôi phải đồng ý với những người khác nói rằng tôi vi phạm MVC. Tôi sẽ đặt 'chi tiết' trong helper. –

+0

Hữu ích nếu bạn giống như Florent2 và cần phải đặt nó như là một phần của thông báo xác thực. Cảm ơn Sam. – RyanJM

+0

Điều này phù hợp với tôi. Tôi không nghĩ rằng nó có ý nghĩa để luôn luôn tuân theo MVC (hoặc bất kỳ nguyên tắc nào) nếu một giải pháp vi phạm nguyên tắc đó rõ ràng là tốt hơn là tuân theo nó. –

-2

Phương pháp trình trợ giúp thường được sử dụng cho tệp Xem. Thực tiễn không tốt là sử dụng các phương thức này trong lớp Mô hình. Nhưng nếu bạn muốn sử dụng thì câu trả lời của Sam là ok. HOẶC Tôi đề nghị bạn có thể viết phương pháp tùy chỉnh của riêng bạn.

+2

Đây không phải là câu trả lời. – Bonifacio2

153

Tôi đồng ý với tất cả các bạn rằng đây có thể là phá vỡ mô hình MVC nhưng luôn luôn có lý do để phá vỡ một mô hình, trong trường hợp của tôi, tôi cần những phương pháp định dạng tệ để sử dụng chúng trong một mẫu lọc (Liquid trong trường hợp của tôi).

Vào cuối tôi phát hiện ra tôi có thể tiếp cận với những phương pháp định dạng tệ sử dụng những thứ như thế này:

ActionController::Base.helpers.number_to_currency 
+6

Điều này là tốt, mặc dù có một cách hơi sạch hơn làm việc đó. Xem [http://railscasts.com/episodes/132-helpers-outside-views] (http://railscasts.com/episodes/132-helpers-outside-views) – user664833

+3

Bài bình luận của Yay trong RailsCasts: Trong Rails 3 in 2013, bằng cách sử dụng một trợ giúp xem trong một bộ điều khiển được thực hiện như view_context.number_to_currency (số tiền) – olleolleolle

+3

Bạn đã nghĩ đến việc sử dụng đá quý "tiền" chưa? Khi đối tượng tiền cung cấp một phương thức format() và bạn có thể gọi nó trong mô hình, bộ điều khiển hoặc khung nhìn. –

3

@ cách fguillen là tốt, mặc dù đây là một cách tiếp cận hơi sạch hơn, đặc biệt là cho rằng các câu hỏi tạo hai tham chiếu đến to_dollar. Đầu tiên tôi sẽ minh họa bằng cách sử dụng mã của Ryan Bates (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 

Thông báo cuộc gọi helpers.pluralize. Điều này là có thể do định nghĩa phương thức (def helpers), đơn giản trả về ActionController::Base.helpers. Do đó helpers.pluralize là viết tắt của ActionController::Base.helpers.pluralize. Bây giờ bạn có thể sử dụng helpers.pluralize nhiều lần mà không lặp lại các đường dẫn mô-đun dài.

Vì vậy, tôi cho rằng câu trả lời cho câu hỏi cụ thể này có thể là:

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 
5

piggybacking tắt của @fguillen 's Đáp lại, tôi muốn ghi đè lên các phương pháp number_to_currency trong mô-đun ApplicationHelper của tôi vì vậy mà nếu giá trị là 0 hoặc blank rằng nó sẽ xuất ra một dấu gạch ngang để thay thế.

Dưới đây là mã của tôi trong trường hợp các bạn sẽ tìm thấy một cái gì đó giống như hữu ích này:

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 
2

Nó không phải là một thực hành tốt, nhưng nó làm việc cho tôi!

để nhập bao gồm ActionView :: Helpers :: NumberHelper trong bộ điều khiển. Ví dụ:

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 

Hy vọng nó sẽ giúp bạn!

3

Bạn có thể sử dụng view_context.number_to_currency trực tiếp từ bộ điều khiển hoặc mô hình của mình.

39

Tôi biết chủ đề này là rất cũ, nhưng ai đó có thể tìm kiếm giải pháp cho vấn đề này trong Rails 4. Nhà phát triển thêm ActiveSupport :: NumberHelper, có thể được sử dụng mà không truy cập vào xem có liên quan đến các module/lớp học sử dụng:

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

Thực sự ngạc nhiên không phải một người đã nói về việc sử dụng một Decorator. Mục đích của họ là giải quyết vấn đề bạn đang phải đối mặt và hơn thế nữa.

https://github.com/drapergem/draper

EDIT: Có vẻ như câu trả lời chấp nhận về cơ bản đã đề nghị làm một cái gì đó như thế này. Nhưng vâng, bạn muốn sử dụng trang trí. Đây là một loạt hướng dẫn tuyệt vời để giúp bạn hiểu thêm:

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

P.S. - @ excid3 Tôi chấp nhận các tháng thành viên miễn phí LOL

Các vấn đề liên quan