Rendering an RJS of controller A in context of controller B - ruby-on-rails

This has been asked before, but didn't receive a proper answer:
I have a User that has Files. When a File is updated (via AJAX) I want to refresh the User view.
I do this in RJS:
page['user'].replace_html :partial => 'users/user'
However, the _user.erb.html partial references other partials in the users directory, and e.g. for _name.erb.html Rails complains it can't find the template Files/name. (I want it to look for Users/name).
Is there a way to change the context of the view rendering to that of controller Users? I'd hate to fully-qualify all of the partial rendering requests.

Maybe try moving the _user.html.erb partial to a 'shared' folder? So the RJS would become:
page['user'].replace_html :partial => 'shared/user'
See http://api.rubyonrails.org/classes/ActionView/Partials.html - a local variable may also need to be defined.

Related

Why would a url_for helper in Rails fail when re-rendering a partial from a different controller?

I have a page with a bunch of widgets that has content that is primarily rendered by the CustomerController. However, there is this other controller called the DigitalItemController that is used to process business logic regarding changes to a customer's item. I have a form that is used to upload a file that is to be handled by a method in DigitalItemController via POST. The form is located in a partial that is named :customer_assets because it contains customer files they have uploaded. This same widget has a table of the files already uploaded with links to them.
The problem I am having is that since CustomerController usually does the rendering, it renders my partial just fine with no complaints. However, when I have the user submit a file for uploading, it calls a method in my DigitalItemController, where the last line of it says to render the partial. When it hits that line, I get an ActionController::RoutingError as it tries to render the partial. The line it doesn't like is:
%td= link_to(item_file.storage_info.s3_key,
url_for(:controller => :data,
:action => :get_storage_information_link,
:digital_item_id => item.digital_item_id,
:digital_storage_id => item_file.digital_storage_id))
I didn't think there would be a problem since the DataController is explicitly used here. It should know I want to just re-render the partial like it did before. However, I get this instead:
No route matches {:digital_storage_id=>#####, :action=>"get_storage_information_link", :digital_item_id=>#######, :controller=>"data"}
Obviously ID numbers here have been censored out, just in case. All I need to do is have that method in the DigitalItemController handle the file upload and then re-render the partial so that the widget shows the correct and up-to-date data. It just seems odd to me that it renders just fine when it is rendered normally, but as soon as the file is submitted, it throws routing errors.
What is the way to fix this?

Rails redirect without changing URL

I've some piece of ruby/rails code.
In one of the controllers say foo i have an action doo which does something and I want to redirect to another controller say bar and action say dar.
When I use redirect_to then URL in the address bar changes to /bar/dar while if I use render then I don't know how to render another controller's view.
I am using rails 2.3.5 so render_component is unavailable for use (which i found could be really really useful for me) -- so as a shortcut if you have any idea of alternate for render_component that will help me infinitely.
Any ideas?
[If am unclear please ask me details]
Instead of a real redirect, could you use an AJAX call to hit the action and pull in the appropriate views?
You can render the same partial from both views. You'll have a view for each action and in each of the views you'll have something like <%= render :partial => "partials/form" %>.
You can just call the action (like calling a function) and then render the template. But accordingly to the MVC pattern you should manage your controller-side logic on the controller and then loads the propper view.

What's the best way to do UJS in rails when you have a re-usable widget?

In my current project I have a couple instances where I have a re-usable form that exists inside a rails partial. This form submits to a specific controller via ajax (:remote => true). The controller does some stuff and then returns back the appropriate js.erb to modify the page via javascript.
This works fine for when I have a single view. But the problem seems to happen when this re-usable partial exists on multiple views. In view 1 I might want to issue a completely different set of javascript commands then in view 2.
As a concrete example, say I have a comments controller that has the normal CRUD operations.
I now have partial called _comments_box.erb. This _comments_box.erb contains the ability to submit a comment via a simple line:
- form_for comment, :url => post_comments_path(post), :remote => true do |f|
This submits to a comments_controller.rb create method which looks somethings like this:
def create
... do some stuff, like create a new comments model
respond_to do |format|
# will respond with create.js.erb
format.js
end
end
The create.js.erb in turn adds a comment to the view, perhaps doing a bunch of other updates to the DOM.
Say I render the _comments_box.erb within a view called post_summary.erb. Now I have another view, post_detail.erb that requires the same _comments_box.erb. However the post_detail.erb requires me to update completely different divs on the DOM in response to a new comment.
I need to create a different JS response for each instantiation. So I can either:
Create an alternate controller method, say create_2. Pass in some parameter to the _comments_box.erb from post_detail.erb to the _comments_box.erb partial so it knows which controller method to fire. This will allow me to have a separate file _create_2.js.erb that will allow me to manipulate the post_detail.erb view independently.
Forget about using js.erb altogether and just use plain old AJAX and get back JSON, and handle the javascript manipulation completely on the client-side.
It seems option 1 allows me to continue to use the UJS supported by Rails which is nice. But also means I probably will be adding a lot of duplicate code everywhere which is annoying. Is there a way for me to do this elegantly while continuing to use UJS?
That's exactly the purpose of Apotomo: http://apotomo.de/
Here is it's own description:
Apotomo is a true MVC widget framework
for Rails. Widgets are based on Cells
and provide reuseable view components.
Having bubbling events, they know when
and how to update themselves via AJAX!
Working with Apotomo widgets almost
feels like developing GUI components –
in a Rails environment.
Have a try, it's great.
I'd not recommend using UJS for frontend apps: server shouldn't take care of client side business. I agree it's useful and clean but it lacks performance and thus should be kept for backend stuff (RJS will move into a gem, see here: http://weblog.rubyonrails.org/2011/4/21/jquery-new-default).
That said, back to the solutions you expose:
1) I think you won't need an extra controller, you'd just have to pass additional params in order to know from where to query came from. A hidden_field could do the trick. With this info, render the good js.erb file
format.js { if condition
render "create.js.erb"
else
render "create_2.js.erb"
end
}
2) I'd go for it and return json but you'll face the same problem: knowing from where the request comes from.
A better solution (than using a hidden_field) might be to check the request.referer in your controller action. This way you leverage the fact that each context has a unique URL, and don't have to explicitly specify another unique value when rendering your widget partial.

How can a partial detect if it's being rendered by a mailer?

I have a partial that is being shared between a few different views, and a mailer template. This partial should attempt to use the user's session to store some state information if possible.
Determining if the session exists seems to be a bit of a problem. Within the partial, calling defined?(session) always seems to yield true during a mail render (is this a bug?), but attempting to access "session" in any way yields an "undefined method" exception.
As of now, I'm having my mailer use a #for_mailer instance variable to signal this partial to render differently, but this doesn't seem very elegant. Is there some simple way for the partial to figure out whether or not it's being rendered by a mailer, as opposed to being rendered in the context of a web request?
I would also create two partials for this but here is an alternative solution as well.
Assuming that it is coming from a different controller and action, you could check the params[:controller] and params[:action].
If you end up doing this more than a few times, you will probably end up with more code than just rewriting the partial. What do you want to be different between the two presentations?

How to use in_place_edit plugin for rails with partials?

I am using the "in_place_editing" plugin for rails to render a form with in-place edits. Thing work fine as long as the default template is chosen by rails (no 'render' method is invoked inside the controller), but they break down when I try to render a partial using "render :partial => 'partial_name'" call. Is this a known issue (in_place_edit does not work with partials?) or am I missing something? I am getting the following error while rendering the partial:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
.../vendor/plugins/in_place_editing/lib/in_place_macros_helper.rb:74:in `in_place_editor_field'
You don't provide anywhere near enough information in your question, giving only two lines of the backtrace and no fragments of the view which does work, or the partial which does not. This means that any attempts to answer you must be based largely on guesswork. That said, the in-place editor helper is just a helper method like any other, nothing special. You can call it from just about any view component. It is highly likely that the way in which that view is included by the controller, or indeed a parent view, is not the reason it is failing.
The helper method is complaining about a nil value. This means that most likely, your partial is invoking in_place_editor_field and passing it values which are not defined in the partial. Check to make sure it isn't using local variables which are not defined, compared to those used in the view where your in_place_editor_field call works; check to make sure that it isn't asking for different instance variables too. In all probability you'll find the views which work are using one variable name while the partial you've tried to render is using another.
The render :partial => ... mechanism supports different ways of explicitly passing in values to the partial; you may choose to use these to clarify your code. See the :locals and :object options for the "Rendering partials" section of the render documentation in the Rails API at:
http://api.rubyonrails.org/classes/ActionController/Base.html#M000658
I am working on a maintenance project which is in rails 2.3.8. And this issue ate a lot of my time
In the view, Change the view to have an instance variable:
#batch = batch
in_place_editor_field :batch, 'priority'

Resources