8

Tôi đang trong quá trình cập nhật ứng dụng Rails 3 để sử dụng Rails 3.1 và là một phần trong đó, đang sử dụng đường dẫn nội dung mới. Cho đến nay, tôi đã có tất cả mọi thứ làm việc ngoài một vấn đề khá khó chịu mà tôi không thể giải quyết.Tài sản biên dịch trước bị hỏng trong Rails 3.1 khi triển khai vào một URI phụ

Ứng dụng và tất cả các tài sản của nó hoạt động tốt trong phát triển, nhưng trong quá trình sản xuất, nó được triển khai tới một URI phụ sử dụng Hành khách (http://the-host/sub-uri/). Vấn đề với điều này là các tài sản được biên dịch trước trong quá trình triển khai và một trong các tệp CSS của tôi (tốt, đó là một tệp .css.scss) đang sử dụng trình trợ giúp image-url từ đá quý sass-rails. Kể từ khi trong quá trình tiền biên dịch, các đường dẫn được mã hóa cứng vào file CSS biên dịch sẵn, tiểu uri không lấy tài khoản của:

Trong file .css.scss tôi:

body { background-image: image-url("bg.png"); } 

Kết quả trong biên soạn application-<md5-hash-here>.css file:

body { background-image: url(/assets/bg.png); } 

gì nó phải được để làm cho nó hoạt động chính xác:

body { background-image: url(/sub-uri/assets/bg.png); } 

Kịch bản này chỉ hỏi quá nhiều? Nếu vậy, tôi sẽ phải chuyển về cách không có đường ống nội dung cũ và chỉ phục vụ hình ảnh và CSS của tôi từ public. Tuy nhiên nó có vẻ giống như một cái gì đó nên đã được suy nghĩ và giải quyết ...? Tôi có thiếu giải pháp không?


Sửa 1: tôi nên lưu ý rằng việc sử dụng các erb solution thay vì mang lại kết quả tương tự, như người ta mong đợi.


Chỉnh sửa 2: để đáp lại lời nhận xét Benoit Garret của

Không, vấn đề không liên quan đến các config.assets.prefix. Tôi đã thử thiết lập điều đó (thành /sub-uri/assets thay vì mặc định là /assets) nhưng hóa ra đó là điều sai phải làm - có vẻ như cài đặt này đã liên quan đến gốc của ứng dụng Rails chứ không phải máy chủ. Loại bỏ (và do đó trở về mặc định) đã cố định tất cả các vấn đề lạ gây ra (và có rất nhiều, tất cả các tài sản kết thúc trong /sub-uri/sub-uri/assets - đó là tất cả rất lạ). Vấn đề duy nhất là người trợ giúp image-url và bạn bè không chọn URI phụ khi chúng được biên dịch trước. Không cần phải nói, điều này là hợp lý vì khi nó được biên dịch trước, nó không thể biết rằng khi nó đang chạy dưới Hành khách, nó sẽ được cấu hình theo cách này. Câu hỏi của tôi là làm thế nào để thông báo cho nó về điều này và do đó kết thúc với các đường dẫn chính xác trong kết quả biên dịch trước. Nếu thực sự nó có thể được thực hiện.

Giải pháp khắc phục hiện tại của tôi là tham chiếu iamge trong CSS như sau: url(../images/bg.png) và đặt nó vào vị trí không được pipelined public/images. Rất lý tưởng vì nó không được hưởng lợi từ dấu vân tay và mọi thứ mà đường ống cung cấp.

+0

Bạn đã thử cái này chưa? http://stackoverflow.com/questions/7295744/how-to-deploy-rails-3-1-app-in-a-subdirectory –

+0

Bản thân ứng dụng được triển khai tốt (nó sử dụng phương thức RailsBaseURI đó vì nó là hành khách đề nghị tài liệu). Tất cả các tài sản được liên kết đến từ bên trong ứng dụng đang chạy như hình ảnh bằng cách sử dụng 'image_tag' và như vậy là tốt. vấn đề duy nhất là các hình ảnh được nhắc đến từ bên trong CSS - nó không biết về URI phụ tại thời điểm biên dịch trước các tài sản. Đó là điều mà tôi cần một giải pháp nếu có. –

+0

Vì vậy, vấn đề của bạn là helper 'image-uri' không nhận' config.assets.prefix'? –

Trả lời

4

Cuối cùng, tôi đã giải quyết một vài giải pháp/giải pháp.

1) Từ https://github.com/rails/sass-rails/issues/17 có vẻ như điều này có thể được khắc phục trong đường ray. Tôi đã giúp những người giúp đỡ khỉ vá lỗi của mình dọc theo dòng của bản vá được đề xuất trong liên kết ở trên.Tôi chỉ cần đặt biến môi trường bắt buộc trong dòng tiền biên dịch tài sản theo số deploy.rb.

Tôi làm tất cả các bản vá khỉ của mình trong một tệp duy nhất config/initializers/gem_patches.rb. Trong tập này, tôi vá phương pháp này như:

module Sass 
    module Rails 
    module Helpers 
     protected 
     def public_path(asset, kind) 
     path = options[:custom][:resolver].public_path(asset, kind.pluralize) 
     path = ENV['PRODUCTION_URI'] + path if ENV['PRODUCTION_URI'] 
     path 
     end 
    end 
    end 
end 

2) Hoặc nếu bạn là ok để nhúng hình ảnh trong CSS, thay đổi kiểu để có một phần mở rộng .erb, và thay thế image-url("bg.png") với url(<%= asset_data_uri "bg.png" %>) sẽ làm việc mà không cần bất kỳ cần phải thay đổi sass-ray. asset-data-uri không tồn tại dưới dạng hàm Sass thuần túy, do đó bạn phải sử dụng trình trợ giúp Rails asset_data_uri.

+0

Tốt hét lên vào điểm thứ hai - điều đó sẽ hoạt động và đó là điều tôi chưa bao giờ cân nhắc. Chắc chắn ít hơn mong muốn, nhưng một cách giải quyết hợp lệ. Đối với điểm 1, bạn có thể làm rõ cài đặt của biến trong 'deploy.rb' không? –

+0

Tôi vừa mới tìm hiểu ý của bạn ... bạn đang tự chạy nhiệm vụ biên dịch trước từ tệp deploy.rb của mình, phải không? Tôi đang sử dụng một cung cấp bằng cách thêm 'load 'deploy/assets'' vào Capfile của tôi - vì vậy không có gì rõ ràng trong' deploy.rb', nơi tôi nên đặt thiết lập biến môi trường. Tôi chắc rằng tôi có thể tìm thấy một nơi khác để thiết lập nó mặc dù. Thậm chí tệ nhất, bạn đã cho tôi một vấn đề để giữ một mắt trên, tốt nhất tôi nghĩ rằng đó là câu trả lời cho ngay bây giờ. Cảm ơn :) –

+0

Chính xác. Trong 'deploy.rb' của tôi, tôi có phần biên dịch tài sản trong tác vụ' after 'deploy: update_code "'. Tôi làm 'chạy 'cd # {release_path}; gói exec rake tài sản: biên dịch trước RAILS_ENV = production PRODUCTION_URI ='/myapp '" 'và sau đó trong helpers.rb khỉ của tôi tôi chỉ cần chọn lên' ENV [' PRODUCTION_URI '] ' . –

0

Sau một chút khám phá xung quanh, tôi đã tìm thấy sự cố. Vấn đề nằm trong Rails, cụ thể là Sprockets :: Helpers :: RailsHelper :: AssetPaths # compute_public_path. Sprockets :: Helpers :: RailsHelper :: AssetPaths kế thừa từ ActionView :: AssetPaths và ghi đè một số phương thức. Khi compute_public_path được gọi thông qua phương thức Sass :: Rails :: Resolver # public_path là sass-rails, helper sprocket rails nhận nhiệm vụ giải quyết tài sản. Sprockets :: Helpers :: RailsHelper :: AssetPaths # compute_public_path sẽ chuyển thành super là ActionView :: AssetPaths # compute_public_path. Trong phương pháp này có một điều kiện của has_request? trên rewrite_relative_url_root như bên dưới:

def compute_public_path(source, dir, ext = nil, include_host = true, protocol = nil) 
    ... 
    source = rewrite_relative_url_root(source, relative_url_root) if has_request? 
    ... 
end 

def relative_url_root 
    config = controller.config if controller.respond_to?(:config) 
    config ||= config.action_controller if config.action_controller.present? 
    config ||= config 
    config.relative_url_root 
end 

Nếu bạn nhìn vào bên trong của rewrite_relative_url_root nó dựa trên yêu cầu phải có mặt và khả năng để lấy được nó từ biến bộ điều khiển để giải quyết gốc rễ url tương đối. Vấn đề là khi sprockets giải quyết các tài sản cho sass nó không có một bộ điều khiển hiện tại và do đó không có yêu cầu.

Giải pháp trên không hoạt động trong chế độ phát triển cho tôi. Dưới đây là giải pháp mà tôi đang sử dụng để làm cho nó làm việc cho bây giờ:

module Sass 
    module Rails 
    module Helpers 
     protected 
     def public_path(asset, kind) 
     resolver = options[:custom][:resolver] 
     asset_paths = resolver.context.asset_paths 
     path = resolver.public_path(asset, kind.pluralize) 
     if !asset_paths.send(:has_request?) && ENV['RAILS_RELATIVE_URL_ROOT'] 
      path = ENV['RAILS_RELATIVE_URL_ROOT'] + path 
     end 
     path 
     end 
    end 
    end 
end 
+0

Tôi có nghĩ rằng đây là bản sửa lỗi giống như câu trả lời khác, nhưng chỉ thực hiện một hơi khác một chút? (có lẽ một chút ngây thơ, không phải là cách tiếp cận khác gây ra cho tôi bất kỳ vấn đề ...) –

+0

https://github.com/rails/rails/pull/2977 –

2

Trong Rails mới nhất 3.1.3 bạn cần phải khỉ vá một mô-đun khác nhau bây giờ, cho nó hoạt động

Đây là những gì tôi đã làm

module Sprockets 
    module Helpers 
    module RailsHelper 

     def asset_path(source, options = {}) 
     source = source.logical_path if source.respond_to?(:logical_path) 
     path = asset_paths.compute_public_path(source, asset_prefix, options.merge(:body => true)) 
     path = options[:body] ? "#{path}?body=1" : path 
     if !asset_paths.send(:has_request?) 
      path = ENV['RAILS_RELATIVE_URL_ROOT'] + path if ENV['RAILS_RELATIVE_URL_ROOT'] 
     end 
     path 
     end 

    end 
    end 
end 

và trong deploy.rb của tôi, tôi có:

desc "precompile the assets" 
namespace :assets do 
    task :precompile_assets do 
    run "cd #{release_path} && rm -rf public/assets/* && RAILS_ENV=production bundle exec rake assets:precompile RAILS_RELATIVE_URL_ROOT='/my_sub_uri'" 
    end 
end 
before "deploy:symlink", "assets:precompile_assets" 
+3

cảm ơn. và tôi thấy rằng trong Rails 3.2 chúng tôi không cần bản vá. chỉ cần chạy lệnh 'bundle exec rake asset: biên dịch trước RAILS_RELATIVE_URL_ROOT = '/ my_sub_uri'" 'và nó hoạt động –

+0

Cảm ơn @SiweiShen, cho capistrano tôi đã thêm một tác vụ trong deploy.rb để chạy trước khi triển khai: asset: preompile, đã làm 'set: asset_env, "# {asset_env} RAILS_RELATIVE_URL_ROOT =/my_sub_uri" ' – Cam

2

tôi đang sử dụng Rails 3.1.3 và triển khai đến một su b-URI thành công. Tôi KHÔNG được vá bất cứ thứ gì.

Các vấn đề chính với thiết lập này đã được thảo luận tốt hơn here. Như bạn có thể thấy, giải pháp đã được áp dụng cho Rails 3.2 và không bao giờ backPorted thành 3.1.4.

Nhưng, tôi đã đến giải pháp bằng Rails 3.1.3 hoạt động cho thiết lập của tôi.

Hãy thử điều này:(Tôi không phải chuyên gia, chỉ cần cố gắng để góp phần giải quyết một vấn đề mà phiền tôi trong nhiều giờ ...)

environment.rb:

#at top: 
ENV['RAILS_RELATIVE_URL_ROOT'] = '/rais' 

sản xuất.rb:

config.assets.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] ? ENV['RAILS_RELATIVE_URL_ROOT'] + '/assets' : '/assets' 

routes.rb:

Rais::Application.routes.draw do 
     scope ENV['RAILS_RELATIVE_URL_ROOT'] || '/' do #see config/environment.rb 
      <<resources here>> 
     end 
    end 

Như bạn thấy, tôi đã đưa assets.prefix bên production.rb, không phải trong application.rb Sau đó bạn làm:

rake assets:clear 
rake assets:precompile 

và hơn, thử nghiệm với giao diện điều khiển:

RAILS_ENV=production rails console 

Kết quả:

foo = ActionView::Base.new 
foo.stylesheet_link_tag 'application' 
=> "<link href=\"/rais/assets/layout.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"/rais/assets/application.css?body=1\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />" 
foo.image_tag('arrow-up.png') 
=> "<img alt=\"Arrow-up\" src=\"/rais/assets/arrow-up-ca314ad9b991768ad2b9dcbeeb8760de.png\" />" 
Các vấn đề liên quan