Rails: How to override stylesheet_path - ruby-on-rails

I've been trying to override Rails' stylesheet_path helper, but I haven't found a way how. I can't just open the ActionView::Helpers::AssetTagHelper module and override it there, because Rails won't pick up my new method.
I know it's probably because the module gets mixed in, so how do I get around that?

Are you doing this so that stylesheet_link_tag will result in something different from normal? If so, just override that in a helper :)
Alternatively, if you really want to override stylesheet_path, you need to also redefine the alias, as, curiously, it's only accessed via its alias (in Rails 2.3.2). For example, I put this in environment.rb and it worked:
module ActionView
module Helpers
module AssetTagHelper
def stylesheet_path(source)
"x"
end
alias_method :path_to_stylesheet, :stylesheet_path
end
end
end
I personally wouldn't go this route but it should work for you if you need it :)

Related

Rails 4 + append_view_path

I want to use dynamic path in my controller in rails gem.
I've added to
module MyGem
class FooController < Config.controller
before_action ->{ append_view_path "app/views/my_gem/#{wizard_name}" }
...
and in views I need to specify path like
app/views/my_gem/#{wizard_name}/my_gem/foo/some.erb
is in Rails some way, to cut the relative path of gem namespace, and get lookup path like?
app/views/my_gem/#{wizard_name}/some.erb
# or
foo/bar/some.erb
Thank you!
UPD:
I understand, that there is way with disabling isolate_namespace in Engine, but I believe, that it is not best and only option.
UPD2: For Rails4 this idea was very useful https://coderwall.com/p/p_yelg/render-view-outside-of-a-controller-in-rails-4
The Devise gem has a way of adding views lookup path by overriding the _prefixes method:
class DeviseController < Devise.parent_controller.constantize
include Devise::Controllers::ScopedViews
# Override prefixes to consider the scoped view.
# Notice we need to check for the request due to a bug in
# Action Controller tests that forces _prefixes to be
# loaded before even having a request object.
#
# This method should be public as it is is in ActionPack
# itself. Changing its visibility may break other gems.
def _prefixes #:nodoc:
#_prefixes ||= if self.class.scoped_views? && request && devise_mapping
["#{devise_mapping.scoped_path}/#{controller_name}"] + super
else
super
end
end
end
Can this be applied to your use case?
See source:
https://github.com/plataformatec/devise/blob/master/app/controllers/devise_controller.rb
Usually, you should only override the partial views or the functions from that gem, do not load from the gem lib like this, because when deploying to the real server it will raise many troubles for you to debug and improve.
You could make your how render method that reads an arbitrary file, interpret the ERB and render it as an HTML page for instance.
ERB.new(File.read(Rails.root.join('foo', bar', 'some.erb'))).result(binding)
By passing binding, the template will have access to the all the variables in the current context.
See ERB docs for more details: http://apidock.com/ruby/ERB
Assuming your gem is an engine, you should be able to simply call render :some in the engine. If the app has a view called <gem_name>/<controller_name>/some.html.erb it will be used.
Also, you can provide a version of that view in your gem that will be used if the app does not yet provide one.
If you need the wizard_name to also be looked up, I think the best way to do that would be to move that portion of the view path to the to the end where you are calling render.
So in your gem's controller you would write render "#{wizard_name}/some" and it would look for that view both in our app's app/views/<gem_name>/<controller_name>/<wizard_name>/some.html.erb and in your gem's app/views/<controller_name>/<wizard_name>/some.html.erb.

Where to put `r` alias for method `render` in Rails?

I my views I want to use r alias for method render.
Following code will do this stuff:
module ActionView
# Make alias for :render method
class Base
alias_method :r, :render
end
end
This it pretty handy and nice for me, however I want to ask, what is the best place for this particular snippet? Currently I put this to my app/helpers/application_helper.rb.

How can I access polymorphic_path inside a model in Rails 4?

Pretty simple, I want to use the polymorphic_path method inside a Rails 4 model. Yes I know it's poor separation of concerns. And I know about Rails.application.routes.url_helpers, but polymorphic_path isn't in there.
Try including also PolymorphicRoutes:
include ActionDispatch::Routing::PolymorphicRoutes
include Rails.application.routes.url_helpers
def link
polymorphic_path(self)
end
I know the OP specified Rails 4 but in case someone else ends up here looking for the answer using Rails 5 like I did, here are two ways to access polymorphic_path in a model in Rails 5:
class Something
# The following line is enough, no need for ActionDispatch::Routing::PolymorphicRoutes in Rails 5
include Rails.application.routes.url_helpers
end
Or, if you want to avoid including all methods, just add a private method that wraps the call and you're good to go!
class Something
def do_stuff
polymorphic_path(a_resource)
end
private
def polymorphic_path(resource)
Rails.application.routes.url_helpers.polymorphic_path(resource)
end
end
Notice that the class doesn't need to inherit from ApplicationRecord, both methods work with POROs (Plain-Old Ruby Object).

Trying to import my helpers into a custom lib/class and suddenly I need a config?

Real simple.
class Template
def stuff_i_want
stylesheet_link_tag('my_stylesheet')
end
class << self
include ActionView::Helpers::TagHelper
include ActionView::Helpers::AssetTagHelper
end
end
And this returns..
undefined local variable or method `config' for Template:Class
from /Users/elephanttrip/.rvm/gems/ruby-1.9.3-p385#shasta/gems/actionpack-3.1.12/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb:137:in `stylesheet_link_tag'
From the stylesheet_tag_helpers.rb in Railtie :
def stylesheet_link_tag(*sources)
#stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths)
#stylesheet_include.include_tag(*sources)
end
Config isn't instantiated in that file anywhere, so I'm assuming its' required from somewhere else.. I have no idea where, or how.
Anyone know how to inject/pass a config into my helper? I've never needed to do this before.
It looks like you're actually including your helpers into Object - and then defining your Template class. I've no idea why it's asking for config, but try putting the includes inside your class definition and see if the problem goes away.
You probably shouldn't be randomly including helpers into things over than your views though - that's not what they're for.
Why not use view_context instead.
So instead of including the helper modules you can do this:
class Template
def stuff_i_want
view_context.stylesheet_link_tag('my_stylesheet')
end
end
This should work fine.
And if you want to include you helpers then use the below code:
class Template
include ActionView::Helpers::TagHelper
include ActionView::Helpers::AssetTagHelper
def stuff_i_want
stylesheet_link_tag('my_stylesheet')
end
end
Ideally you should not include helpers in ur controllers as they are not intended for that.
Hope that helps

Multiple Rails Helpers w/ Same Method Name

I have two different helper files (photos_helper & comments_helper) w/ that have a method named actions_for. How can I explicitly call which helper method that I need? I know that I could just rename one of them but I would prefer to keep them the same. I tried PhotosHelper::actions_for but that doesn't seem to work.
In Rails 3 all helpers are always (in Rails 3.1 a patch exists to selectively allow helpers again) included. What's happening behind the scenes:
class YourView
include ApplicationHelper
include UserHelper
include ProjectHelper
...
end
So depending on the order Rails includes them, any of your actions_for methods will be used. There is no way you can explicitly chose one of them.
If you would have to explicitly call ProjectHelper.action_for, you could also name your methods project_action_for - simplest solution.
Make both of them a Class Method
module LoginsHelper
def self.your_method_name
"LoginsHelper"
end
end
AND
module UsersHelper
def self.your_method_name
"UsersHelper"
end
end
Then in View
LoginsHelper.your_method_name #Gives 'LoginsHelper'
AND
UsersHelper.your_method_name #Gives 'UsersHelper'

Resources