How to use in_place_edit plugin for rails with partials? - ruby-on-rails

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'

Related

Confused about how the render works in rails

I'm still fairly new to rails, but I've been trying to figure it out by building a bunch of simple projects like blogs, forums, clones over the weekend.
One of the blogs that I'm working on is a typical blog with users(devise), posts, and comments. I've been following a tutorial for this.
The thing that I've been really confuse on is setting up the comments and rendering it.
The tutorial teaches me to make a partial for comment in the comment view named _comment.html.erb and then another for form _form.html.erb . I fully understand that to call the form i just do render 'comments/form' but for the comment.html.erb i need to render #post.comments how come it's not 'comments/comment'? Why is it comments with the S?
I've tried reading up on render and plurization on rails, but most of them just talk about the model.
There are two convention over configuration things going on here that may be causing you some confusion but are meant to save time.
Rails will automagically find the right partial if it follows naming conventions, meaning if your model is Comment that the view partial is located in app/views/comments/_comment.html.erb. That means you don't have to specify the location of the partial when calling render, but instead can just pass the model object directly and Rails figures out that you want it to render the partial and finds it on its own.
The reason it's comments plural here is that you are rendering all of the comments as a collection, not just a single comment. It's a convenience feature to allow the developer to simply tell Rails to render a collection and it will automagically know to use the corresponding partial. It's identical to typing:
#post.comments.each do |comment|
render 'comments/comment`, object: comment
end
Note how the above code is calling render directly on a model object so we don't have to bother specifying the location of the partial (again, assuming you followed the convention when naming and locating things). If we named the partial something else, then we'd have to specify the location like your other examples.

Rails routes. How does the process explicitly work?

I've created a few apps using Ruby on Rails now, but there's a few concepts that I haven't quite been able to get my head around.
One of these is how does the 'routing' process work? By that I mean, where a user enters a URL string and Rails serves the relevant assets in response to the URL.
Here's what I think is happening:
A user browses to the server using their browser:
http://0.0.0.0:3000
They then prepend their URL with a string:
http://0.0.0.0:3000/entries/view_all
Rails' 'routes.rb' file specifies what the string should actually relate to via directives:
match "/entries/view_all" => "entries#view_all"
This above directive says that when the string "/entries/view_all" is prepended to a URL, execute the method view_all, found in the file 'entries_controller.rb'.
The view_all method is executed:
def view_all
#entries = Entry.all(:order => 'created_at DESC')
end
It assigns all the entries from the table 'Entry' to the constant #entries, in descending order.
Rails then magically knows to serve the user the 'view_all.html.erb'.
An each loop inside the 'view_all.html.erb' displays relevant information from the 'Entry' table:
<% #entries.each do |entry| %>
<h1><%= entry.title %></h1>
<p><%= entry.content %></p>
<p><em>Posted at <%= entry.created_at %></em></p>
<% end %>
My questions are as follows:
How wrong is my concept of how things work?
In step #3 above, how does Rails actually know the view_all method is found inside 'entries_controller.rb'? The directive was entries#view_all, not entries#view_all. Does Rails automatically match the start of the controller file names inside the 'controllers' directory, and ignore the '_controller.rb'?
In step #6 above, how does Rails 'magically' know to serve the 'view_all.html.erb' view? Is it similar to how I think it works in question #2? Does Rails match the 'view_all' part of the file name with the name of the method found in 'entries_controller.rb'?
How is the object/constant #entries, and all its methods, "passed on" to 'view_all.html.erb' from 'entries_controller.rb'?
In response to (2) and (3) - Rails emphasizes convention over configuration, which results in seemingly magical coupling between the router, controllers, and view templates. For example, the router knows that entries refers to an EntriesController class because there's a line in ActionDispatch::Routing::RouteSet:
def controller_reference(controller_param)
controller_name = "#{controller_param.camelize}Controller"
...
It's not magic - the "Controller" word is hard coded. It's just what Rails was programmed to expect given your inputs. And it's like this all over the place, which can be a bit daunting to comprehend when you're starting out with it (have a look at Ember.js for even more daunting magic like this).
In response to (4): Rails copies your individual instance variables into an ActionView instance. There is fairly significant contention in the community over whether it should really be doing this, but for now that's how it works, and you should keep that in mind when you are writing your controller actions. You don't want a lot of overhead in copying numerous or bloated objects that you don't need in the view.
You got it, actually. It's all name matched. The Entry model matches up with the entries_controller which matches up with the entries view. The name of the specific view correlates with the controllers action.
#entries is an instance variable (called such as it's an instance of the whole model), as is any variable that starts with an #. Those variables in the controller are the ones that are available to the corresponding view.
A neat trick to use is the _enrty partial.
_entry.html.erb
<h1><%= entry.title %></h1>
<p><%= entry.content %></p>
<p><em>Posted at <%= entry.created_at %></em></p>
Then in places that you want to call the index (your view_all is typically labeled as index), or parts there of, you can <%= render #entries %>
But yeah, a lot of the magic of rails is in the matchy matchy naming conventions. There are ways around that, as everything is customizable, but that sums it up. Cheers!
1) How wrong is my concept of how things work?
Thats a pretty good way of thinking about how the process works
2) In step (3), how does rails actually know the 'view_all' method is found inside 'entries_controller.rb'? The directive was 'entries#view_all', not 'entries#view_all'. Does rails automatically match the start of the controller file names inside the 'controllers' directory, and ignore the '_controller.rb'?
Rails abides by a directive called "Convention over configuration", this means Rails will behave a certain way, as long as you give it instructions in the way it expects. So in your query above, because you specify the "entries" part of your controller it knows to go look in "entries_controller" for the "view_all" action
3) In step (6) how does rails 'magically' know to serve the 'view_all.html.erb' view? Is it similar to how I think it works in question 2? Does rails match the 'view_all' part of the file name with the name of the method found in 'entries_controller.rb'?
Convention over configuration aka "magic". Once Rails executes an action, it will look for the matching template to execute based on your request. if you made a request for an json page (by altering your request headers for example), it would look for view.json.erb. If you left out that template it would throw an error unless at the end of the action you used a render call to tell it to do something else
4) How is the object/constant '#entries', and all its methods, 'passed on' to 'view_all.html.erb' from 'entries_controller.rb'?
It just is :D, or are you asking to see the rails source code that is responsible for that?
ActionView (Views) and ActionController(Controllers) both inherit from Actionpack, so I imagine its not that hard to share variables between the two.

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?

Should you only use local variables in a partial?

Using local variables seems advisable in a partial that could be used application-wide to avoid dependencies across the application.
But within a single controller it seems acceptable to reference instance variables that you know will be available in all of the actions that use the partial.
If you do this, there seems to be a risk, however, that a particular action may get changed to no longer provide the instance variable to its view. Then the partial would stop working. I'm not sure if this is really a problem, though, since a regular view would encounter the same risk.
Does it matter if you reference instance variables in a partial?
You're on a roll today! :-)
You can pass variables into the partial as :locals to keep this all nice and clean. For example,
render :partial => 'my_partial', :locals => { :some_variable => some_variable, :some_important_value => 'an important point!' }
These variables are then available in the partial view:
<%= some_variable %>
<%= some_important_value %>
However, there is nothing specifically wrong with using instance variables in your partials.
i would only recommend using instance variables as long as the partial is not shared, since this can get confusing very fast ;)

Resources