How to render js template from module included in controller?
Asked Answered
B

2

3

I have an action in a controller concern, which gets included in a controller. This action does not render a js.erb file as specified under a respond_to block. How do I properly get an action in a controller concern to successfully render a js.erb file (or any view, for that matter)? Is it a problem with my routes?

The link for the module action

= link_to image_tag("upvote.png"), 
send("vote_socionics_#{votable_name}_path", votable, vote_type: "#{s.type_two_im_raw}"),           
id: "vote-#{s.type_two_im_raw}",           
method: :post,          
remote: true

** The link for the controller action**

= link_to "whatever", characters_whatever_path, remote: true

controllers/characters_controller.rb

class CharactersController < ApplicationController
  include SocionicsVotesConcern

  def an_action
    respond_to do |format|
      format.js { render 'shared/vote_socionics' }   # This renders/executes the file
    end
  end

controllers/concerns/socionics_votes_concern.rb

module SocionicsVotesConcern
  extend ActiveSupport::Concern

  def vote_socionics
    respond_to do |format|
      format.js { render 'shared/vote_socionics' }   # This DOES NOT render/execute the file. Why?
    end
  end

end

views/shared/whatever.js.erb

  # js code that executes 

routes.rb

  concern :socionics_votes do
    member do
      post 'vote_socionics'
    end
  end

  resources :universes
  resources :characters,  concerns: :socionics_votes
  resources :celebrities, concerns: :socionics_votes
  resources :users,       concerns: :socionics_votes
Botti answered 16/7, 2014 at 5:34 Comment(2)
Have you tried to extend module from ApplicationController ?Duthie
if so, then is including a module as a controller into a controller not a problem? This gave me the error as follows wrong argument type Class (expected Module)Botti
B
4
module SocionicsVotesConcern
  extend ActiveSupport::Concern

  included do 

    def vote_socionics
      respond_to do |format|
        format.js { render 'shared/vote_socionics' }
      end      
    end

  end

end

Wrap any actions/methods you define in the concern in an included do block. This way, anything in the block will be considered as if it was directly written in the includer object (i.e. the controller you're mixing this into)

With this solution, there are no loose ends, no idiosyncracies, no deviations from rails patterns. You will be able to use respond_to blocks, and won't have to deal with weird stuff.

Botti answered 20/7, 2014 at 1:38 Comment(4)
There should be more explanation in this answer.Humankind
Instead of doing a response to block, you just render the partial. I don't know if the variables from the controller action are available. I'm pretty sure they're ate a lot of word and bag stuff with this. All I know is it worked for this specific purpose of rendering a js file.Botti
You should say that in the answer itself.Humankind
updating with a better answer.Botti
S
1

I don't think this is Rails compatible man.

  • A controller action renders a view or redirects;
  • A module has methods. Methods executes code;

So just including the methods from a module named as a controller is not gonna work. What you really need to do is to call an action from controller A to controller B.So SocionicsVotesController would turn into a real controller class and you would use the redirect_to rails method.

You would have to specify the controller and action you're redirecting to, like:

redirect_to :controller => 'socionics', :action => 'index'

Or just:

redirect_to socionics_url

Which will send a HTTP 302 FOUND by default.

EDITED:

If you want to reuse the way your controller actions respond, while using rails 4 concerns, try this:

class CharactersController < ApplicationController
  include SocionicsVotesControllerConcerns  # not actually a controller, just a module.

  def an_action
    respond
  end


module SocionicsVoteControllerConcerns
    extend ActiveSupport::Concern

    def respond
      respond_to do |format|
        format.html { render 'whatever' }
        format.json { head :no_content }
      end
    end
end

I only got it to work when changing format.js to format.html, maybe because of this.

Sibie answered 16/7, 2014 at 6:40 Comment(9)
the reason i have SocionicsVotesController as a module is because this goes into three different controllers (with models) for a polymorphic association. all of the related private methods would also go in each actual controller as well. Should i just repeat myself and put them in each controller without a module? I feel like this pattern will eventually come up, so i might as well learn how to do it now.Botti
Isn't this kind of stuff what concerns were designed for in rails?Botti
Concerns reinforce code reuse, sure. But if you want to respond with the same resource time and time again, maybe you should reuse your controller, not write 3 different ones. But, ok... lemme see how you can use concerns to do what you're trying to do.Sibie
hrm. that's a shame because i need it to be js for doing ajax-y stuffsBotti
I see. But that is still doable. But of course, it's another problem.Sibie
No, its actually the main problem. Your answer answers another problemBotti
A polymorphic association implies multiple resources. I'm not writing 3 diff controllers for the stuff that I put in the concern.l, or for the 1 resource. The point is to add in a concern module to a resource controller to give that resource some functionality. That's the whole point of a concern. I only showed one resource because showing more is irrelevant to the problem.Botti
So, all you wanted was just to make format.js work inside your module?Sibie
Let us continue this discussion in chat.Sibie

© 2022 - 2024 — McMap. All rights reserved.