Why is render :text => #object.inspect not working [debugging in rails]? - ruby-on-rails

I have in my controller something very straightforward:
def show
#group = Group.find(params[:id])
render :text => #group.inspect
end
I know that #group exists because if I send it to view (by commenting out the third line), it shows everything correctly. However, when I includethat render text line, I get simply a "#" and nothing else. What am I doing wrong?

It is rendering correctly if you view the source of the page. The problem is that the output is something like this:
#<Group id: 123, ...>
The browser expects HTML, so when it sees the opening bracket it thinks it's an HTML tag (but it's really not valid HTML).
Instead you could try escaping the HTML first:
render :text => CGI.escapeHTML(#group.inspect)
This will replace < with <, etc., properly displaying what you expect.

Related

Passing rails variable to liquid works in console but not in view

I want to pass a hash to the render method. In my console everything works fine when I do this:
#object = Object.find(params[:id])
#hash_object = #object.to_liquid
#template = Liquid::Template.parse("Welcome to {{object_title}}")
#template.render('object_title' => #hash_object["title"])
But when i want to render the page through my controller and pass it through an app-proxy which expects vanilla liquid, the hash-key isn't appearing. But it's interpreted, because the view shows blank space. If it wouldn't work at all, the view would show:"Welcome to {{object_title}}" or don't even load because of syntax errors.
I tried almost every possible way to render the template. The next two tryouts are the ones which do not throw an error, but show only a blank where the title should appear:
#pageview = Liquid::Template.parse(File.read(Rails.root + "app/views/app_proxy/show.html.erb"))
render text: #pageview.render('object_title' => #hash_object["title"]), content_type: "application/liquid"
And the second one (which I think is a bit cleaner and more rubylike):
respond_to do |format|
format.html do
render text: #pageview.render('object_title' => #hash_object["title"]), layout: false, content_type: "application/liquid"
end
end
Where is the mistake in these renderings or what am I missing?
# variables are assigned to an instance of a class, not the class itself, so you need to declare it an "initialize" method (or "setup" method, if a test)
render html: instead of render text:

Dynamic rendering of partials in Rails 3

In the app I'm working on, I have defined a method task_types in the model:
task.rb
def self.task_types
["ad_hoc"]
end
I use task_types to populate a drop-down menu, but I would also like to use it to dynamically render a partial.
What I have in mind is, for each task type, there will be an associated comment box. I went ahead and made a helper that will call the correct partial depending upon which task type was selected:
#tasks_helper.rb
module TasksHelper
def completion_comment(task)
task_types = #task.task_type
render :partial => "#{Task.task_types}", :locals => {:task => task}
end
end
Unfortunately, when I called completion_comment, I received the error message "The partial name (["ad_hoc"]) is not a valid Ruby identifier."
What I'm looking for is a dynamic way to render the appropriate partial. I think I'm on the right track, but I'm not sure how to extract the array elements from my task_types method (as you can see in the error message, the brackets and quotation marks are getting pulled into the render action). Or, perhaps I need to utilize a different method for dynamically rendering the partial. Any help is appreciated.
Here's what worked:
module TasksHelper
def render_task_form(task)
render :partial => "/tasks/completed/#{task.task_type.downcase}"
end
end
I had tried this solution much earlier, and had received an error that "The partial name (/tasks/completed/) is not a valid Ruby identifier; make sure your partial name starts with a letter or underscore, and is followed by any combinations of letters, numbers, or underscores."
I tried it again, and to remedy this problem I deleted all tasks from the database. Now the partial renders dynamically. Hopefully this helps someone else!
You need a string instead of the entire task_types array. #task.task_type should return a key that a) matches an element in the task types array and b) matches a known partial.
The following is a bit more complicated that it needs to be but should do the trick:
tasks_helper.rb
module TasksHelper
def completion_comment(task)
if Task.task_types.include? task.task_type
render :partial => task.task_type,
:locals => {
:task => task
}
else
# render a generic comment box here
end
end
end
In Rails 4, the view or the partial name is supposed to respond to a valid Ruby identifier.
So, the entire view name must follow the same format as a ruby-identifier:
it should start with a _ or character
it cannot start with a number
it can have only _ and alphanumerics.
So, considering that task_type is a valid ruby identifier (which it should be), it will work. In generate this code will not work in Rails 4
render '/tasks/completed/some-task'
but this will work
render '/tasks/completed/some_task' # note the underscore.

Rendering text before and after an action works

I have an application with a sometimes longer executing action. How might I, if possible, render placeholder text such as 'processing...' before the action executes and replace the page with the result of that action, given that you can only issue a render once per action?
the :text option of the render method accepts a Proc object:
render :text => proc { |response, output|
5.times do |i|
output.write("Hello, friend\n")
sleep 3
end
}
Your example might look like :
render :text => proc {|response, output|
output.wirte("Processing..")
results = perform_something
output.write(results)
}
As you see, the 'output' here is an writable IO-like object. But still, you should avoid using it whenever possible. You can show the 'Processing ...' message with javascript easly here, then receive an xhr back from controller once you have the results to display

Partial not updated on first click

I am having problems with a remotely executed action and a partial that doesn't update the first time I click the link.
Inside the view (a partial named books) I am creating a link:
link_to "⊗", read_book_path(book), :remote => true
The read_book_path is defined in routes.rb
There is also a conditional that displays a different text when that book is read.
Inside my controller, I have defined a new action:
def read
#books = Book.all
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
respond_to do |format|
format.html { redirect_to(books_url) }
format.js {render :layout => false, :locals => { :book => #book } }
end
end
This means I need a file read.js.erb, this file's content is:
$("#books").empty().html("<%= escape_javascript( render(:partial => "books") ) %>");
When I click the link, I can see in the terminal window that the database field is updated but the partial is not. Clicking the same link again updates the partial.
Changing the link to :remote => false also works but the page reloads (as expected).
I have tried to debug it with Safari and the Developer tools and I can see the server's response when clicking the link for the first time.
Something is wrong there, the HTML generated by <%= escape_javascript( render(:partial => "books") ) %> contains the wrong HTML with the old content of the partial. Only the second or third click shows the updated HTML.
I have integrated jquery-ujs - is that the reason the partial doesn't update the first time or am I missing something else?
This really gave me a headache, can you help me?
Edit:
If that helps: I created a listener in application.js to ajax:before and ajax:complete. The first one shows a little spinner, the second one hides it.
When I click the link, the spinner shows but it doesn't hide.
It looks like you have an ordering problem that's causing the trouble. You're capturing a complete set of books into the #books variable and then modifying a separate copy of a single book. This change will not be propagated back.
# Load and modify the one book by flipping the flag
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
# Load all books
#books = Book.all
As a note this is an extremely inefficient way of doing things, so I hope you're not working on a large amount of data. You might find it's easier to do this by simply toggling the one field with a simple UPDATE query:
Book.update_all({ :read => true }, { :id => params[:id] })
I'm not sure why you're calling $(...).empty().html(...) instead of simply $(...).html(...) since the html() method should replace the HTML wholesale with no need to clear it in advance.
One thing that might help is using .js.rjs where the equivalent would be:
page[:books].replace_html(:partial => 'books')
With simple JavaScript, RJS allows you to eliminate a lot of the drudgery. You can use JS in RJS as well for cases where there is no equivalent:
page << '$("#books").empty()'
page[:books].replace_html(:partial => 'books')
To make this more Rails friendly, you could call your partial _book which would make the local variables redundant. Each partial has a default variable with a name matching the template name:
render(:partial => 'book', :collection => #books)

Render multiline text with Rails?

I'd like to render multiline text in Rails, the action looks like:
def mutli_text
render :text => 'Word1\nWord2'
end
and I'd expect the response to be :
Word1
Word2
unfortunatly I get Word1\nWord2
Any help would be appreciated
(The action must render a multiline response to get the autocomplete jquery plugin working)
"Word1\nWord2"
You have to use double quotes to be able to use escaped characters.
But if you want to have that actually be a line break in the browser, you need to make it an actual html tag.
'Word1<br/>Word2'
Or even:
"Word1<br/>\nWord2"
you can actually do something like this:
(render :text => "line1\nline2").gsub("\n",'<br />')
It at least works on #render within a view (using HAML). I haven't tried it within a controller action.
Just render the text as plain. You can even change the content type to csv if you want to.
render :plain => 'Word1\nWord2', :content_type => "text/csv"

Resources