newbie: render different view and layout based on condition loose #object access - ruby-on-rails-3

I am trying to render a view + layout based on a condition. The following code seems to work but loses access to #objects set upfront. I call this code in a ProfilesController method Show.
#profiles = Profile.where(:user_id => current_user.id).first
if #profile.nil? == true
render :view => "show",
:layout => "application"
else
render :template => "profiles/my_profile",
:layout => "profiles"
end
Gives output:
undefined method `profiles' for nil:NilClass
How could one render based on a condition and still preserve the previous set #objects (in this case the access to #profiles)

Setting layout in view is not the way to go, its not the rails way and was not advised so even if possible. I changed setting layout in controller action and render the right code in my show partial wich complete solved the issue.

Related

Updating various DOM elements after best_in_place update

I have various values in a table that need to be updated after a DOM element is updated using best_in_place. How can you trigger a javascript action like "create.js.erb" called "update.js.erb" after a best in place update?
For example, I have a table of item prices, and I need the table's "total" field to update after a user updates an individual item quantity.
I've seen many people asking this question, but haven't found a satisfactory solution. I found the best approach is to create a javascript function that watches for a particular DOM element to update after an ajax:success, and then use jQuery to update a specified DOM element.
In the controller of the item being updated, I package a JSON response that includes all of the information my javascript will need in order to update DOM elements.
You'll see I also render the new table row's partial as an HTML string, and pass this string along with the JSON response.
___Item Controller_____
respond_to do |format|
if #item.update_attributes(params[:item])
#json response variables to refresh table row after update
id = [#item]
new_row = render_to_string('items/_item.html', :layout => false, :locals => { :item => #item })
#----------json-variables-----------#
format.json { render :json => { new_row: new_row, id: id, :status => 200 }}
format.js
else
format.json { render :json => #item.errors.full_messages, :status => :unprocessable_entity }
format.js
end
end
Then in a .js file that gets loaded with the page (like application.js), I include a function that watches for a table row with class "row_class" to be updated.
$(document).ready(function(row_class, row_id_prefix){
$("." + row_class).on("ajax:success",function(event, data, status, xhr){
var parsed_data = jQuery.parseJSON(data); //parses string returned by controller into json object
var id = parsed_data["id"];
var new_row = parsed_data["new_row"]; //this is an html string that replaces the existing table row
$('tr#' + row_id_prefix + id).replaceWith(new_row);
$('tr#' + row_id_prefix + id).effect('highlight');
$('.best_in_place').best_in_place(); //activates in-place-editing for newly added content.
}));
You can modify the jQuery to update any DOM element you need. Also, if you need the results of ruby methods called on objects (such as a humanized total, tax total, etc) you can define these as variables in the JSON object in the controller.
Ultimately it'd be best if best_in_place would trigger (in this case) the items/update.js.erb script, but it doesn't look like that's on the roadmap.

Render a template to the database

I'm trying to wrap my around a task and haven't found anyone who has address this issue.
I'm created an awards nomination system.
Anon user submits nomination
Admin user generates a merged letter from template and edits letter
Letter text is saved to database to later generate PDF
I read that you can render an ERB text to a variable. This is working great but then I'm stuck with the text because of the Double Render Error.
def generate_letter
#submission = Submission.find(params[:id])
#submission.letter_text = render (:text, :layout => false, :template => 'submissions/generate_letter') and return
#submission.save
redirect_to #submission
end
Is there a better way to generate this text for the database or a workaround to redirecting? I was trying to avoid keeping my merge template in the code and ERB seems a nice way to handle it.
You need to use render_to_string. This line
#submission.letter_text = render (:text, :layout => false, :template => 'submissions/generate_letter') and return
should be
#submission.letter_text = render_to_string( template: 'submissions/generate_letter.text.erb', layout: false )

detect if a form is submitted with ruby on rails?

Is there a way to detect if a form is submitted? Im trying to set a class based on a custom validation something like below example, is that possible?
.control-group{ :class => ("error" if form_is_submitted ) }
Now trying :
.control-group{ :class => ("error" if params[:user][:profile_attributes][:gender] == nil) }
This fails if the form is not submitted because then the params are nill and throws an error
If your form data is submitted through fields with name attributes like user[profile_attributes][gender] (all having the user prefix), you can check if the :user exists in params.
... if params.include?(:user)
If for some reason (like coming from the route) params[:user] is already going to have a value even for GET requests, you can look for a specific form field having a value. For example, you could add a hidden field
<%= f.hidden_field :some_field, :value => true %>
and check for it in your condition
... if params[:user].include?(:some_field)
You can alternatively check if the request is via the POST method
... if request.post?
This works for other methods as well, like request.put? for an update method.

Have I coded myself into a corner with this custom route?

I don't even know how to write a proper title for this. I kind of cobbled together some routing code based on a bunch of different articles, and now I'm wondering if I've painted myself into a corner.
I've got a NewsArticle model, and I want the links to look like this:
/news # List of all articles
/news/2011 # List of articles published this year
/news/2011/06 # List of articles published this month
/news/2011/06/28 # List of articles published on this day
/news/2011/06/28/my-post-title # Actual article
Ok, going against the Rails way already, but so be it.
I've got routes setup like this:
controller :news_articles, :via => [:get] do
match '/news(/:year/(/:month(/:day)))' => :index, :constraints => { :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/ }
match '/news/:year/:month/:day/:id' => :show
end
Note there is no :as declaration. That's because when I do add something like :as => "news_archive" then I end up with news_archive_path which returns something stupid like "/news?year=2010&month=4". So, I excluded that bit and wrote my own path methods in my application helper file:
def news_archive_path(year = nil, month = nil, day = nil)
return "/news" if year.nil?
t = Time.zone.local(year.to_i, month.nil? ? nil : month.to_i, day.nil? ? nil : day.to_i)
if month.nil?
"/news/#{t.year}"
elsif day.nil?
"/news/#{t.year}/#{"%02d" % t.month}"
else
"/news/#{t.year}/#{"%02d" % t.month}/#{"%02d" % t.day}"
end
end
def news_article_path(article)
t = article.published_at.in_time_zone
"#{news_archive_path(t.year, t.month, t.day)}/#{article.friendly_id}"
end
Great, this all works in practice. But now I've run into a problem where I'm testing my controllers and I want to make sure that the right links appear on the rendered templates. (Oh yeah, I'm not keeping separate view tests but instead using render_views in my controller tests.) But the tests are failing with the error undefined methodnews_article_path' for #`.
So, have I just approached this all wrong and painted myself into a corner? Or can I get out of this by somehow including the helper methods in the controller test? Or do I just suck it up for the sake of getting the test to pass and hardcode the links as I expect them to be?
To make news_article_path available you need to do:
class MyClass
include Rails.application.routes.url_helpers
end
Now MyClass#news_article_path will be defined. You can try to include the url_helpers into your test case. I've seen that break recently with "stack level too deep" errors (it creates an infinite recursion of "super" calls in initialize). If it doesn't work, create your own view helpers class and do "MyViewHelper.new.news_article_path" etc.
It's probably not a good idea to be generating the paths by concatenating string in your path helpers. Instead, simply use the url_for() method. Eg:
def news_article_path(article, options = {})
url_for(options.merge(:controller => :articles,
:action => :show,
:id => article.id,
:year => article.year,
:month => article.month,
:day => article.day))
end
(This assumes day, month, year are added as quick methods on your model, eg:
def year
self.published_at.in_time_zone.year
end
For your tests, either include the helper methods via something along these lines: My helper methods in controller - or use the url_for method again.
...That said - as you suggested, testing views within controller tests isn't ideal. :)

Rails 3 + MongoDB: Render Json Without a Field

render :json => #bs.to_a.to_json, :except => ["completo"]
I want to render everything to json except the field "completo". That should be working but given that I need to do ".to_a" and ".to_json", that stopped working. Is there a way to revert that?
Thanks
Assuming that #bs is a MongoDB Cursor, do the following:
#bs = #bs.to_a.map { |obj| obj.delete("completo"); obj }
render :json => #bs.to_json
In summary:
Make it an array.
Remove the completo key from every item in the array, making sure we return the item itself at the end of the map
Render as before.