Rails 3 - Dynamically change out css class based on Controller name - ruby-on-rails-3

I have a Rails 3 application that is using the 960 grid CSS layout(s). There are a couple of different views that stretch in width and I am trying to come up with a good way to dynamically change out those classes.
For Example:
My Devise Controllers (Sessions, Passwords, etc) all use a certain class to restrict the width to 340px, while most of my other controllers use another class to restrict the width to 540px
So my 340px layout uses class names grid_6 push_5, while my 540px layout uses grid_10 push_3
Anyway to grab the accessed controller in the application_controller? My thinking is to just get the controller and have a switch statement that sets the class names in a helper_method.
Thoughts?

I was able to figure it out, thanks to this post: Determine the requested Controller in - ApplicationController
Here is how I ended up doing it (application.html.erb):
<%= render :partial => 'common/content_container', :locals => { :controller => params[:controller] } %>
content_container partial:
<% case controller
when "sessions", "passwords"
container_div_grid_number = "6"
container_div_push_number = "5"
else
container_div_grid_number = "10"
container_div_push_number = "3"
end
%>
<div class="grid_<%= container_div_grid_number %> push_<%= container_div_push_number %> ">
<div class="top_<%= container_div_grid_number %>"></div>
<div class="middle_<%= container_div_grid_number %>">
<%= yield %>
</div>
<div class="bottom_<%= container_div_grid_number %>"></div>
</div>

Related

How do I update a list of partials rendered with a collection after a form submission of a newly created object in ruby on rails

This is a portion of my groups view. I have a list of partials that I render with a collection of objects:
<div id="container">
<ul>
<li id="form"></li>
<li id="partials">
<%= render :partial => 'groups/partial-list-row', :collection => #allpartials, :as => :f %>
</li>
</ul>
</div>
In the list item with id "form" there is a ruby on rails form that is a form_for #newpartial which is defined in the Partial controller as #newpartial = Partial.new(). I have successfully used jquery to toggle the show and hide of the two list items on a "New Partial" button click, and upon completing a finished form, a new partial object is definitely created. What I'm looking for here is the collection of partials that reappears after the form submission includes the newly created partial object. What is the best way to do this? My form which sits inside the list item with id "form" looks like this:
<%= form_for #newpartial, :html => {:multipart => true, :class => 'custom'}, remote: true do |f| %>
<% if #newpartial.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#newpartial.errors.count, 'error') %> prohibited this partial from being saved:</h2>
<ul>
<% #newpartial.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render :partial => 'partials/form-partial', :locals => { :f => f } %>
<div class="actions">
<%= f.submit 'Launch', :class => 'large success button radius new_browser_tab' %>
<a class="cancel_campaign_new">Cancel</a>
</div>
<% end %>
I also have successfully created a function that is bounded to the "ajax:success" event of this form after the DOM is fully loaded. I just don't know if this is a right approach, and if it is, I don't know what the body of this event handler should consist of. I have created other questions relating to this same issue (I haven't found a solution to this for quite some time now). Here are the questions if you want additional context:
SO question 1
SO question 2
What I was failing to realize is that applying the remote: true on the form indicates that the controller's action method will respond with the models "action".js.erb file. After creating that file and performing the jquery I had always intended, I was able to fix a few kinks and got that part working.
The difference between putting the jquery to render the new partial in your client side javascript and your "action".js.erb file is that the "action".js.erb file is able to make the required request to the server, whereas your client side javascript is not.
Can someone read this and let me know if the above statements are accurate? I'd really like to provide an answer that is accurate as possible for anyone that comes across this...
There are some really good tutorials at CodeSchool.com which has some free courses to take that include video lectures, slides, and exercises that I used to finally give me enough guidance on this. Also worth mentioning that if you intend to learn this stuff quickly and plan on spending a lot of time developing your web development abilities, paying the 20 dollars a month for access to all the courses is well worth it (you can cancel at any time, so learn what you need to learn and move on!).

how to render partial on everything except a certain action

I have a _header.html.erb partial which is where I put my navbar
on my launch page I don't want to display the navbar.
this is the body of application.html.erb
<body>
<%= render 'layouts/header' %>
<div id="container">
<%= yield %>
</div>
</body>
How do I render it on every action except specific actions on specific controllers?
Replace your render with this:
<%= render 'layouts/header' unless #disable_nav %>
Then you can simply set disable_nav to true in any controller action you like:
def landing_page
#disable_nav = true
end
As a before_filter, which I'd encourage over the above:
application_controller.rb
def disable_nav
#disable_nav = true
end
my_controller
before_filter :disable_nav, only: [:landing_page]
You can put that logic in your stylesheets, in your controller or in your views (this last one, only for whole controllers).
Stylesheets
If you want to add the logic in your stylesheets, first add to your body tag the following classes:
<body class="<%= "#{controller.controller_name} #{controller.action_name}" %>">
Then, in your css, add something like this:
body.controller.action .navbar {
display: none;
}
Controller
To add this logic to your controller, add a before filter to your application controller:
class ApplicationController < ActionController::Base
before_filter :show_navbar
protected
def show_navbar
#show_navbar = true
end
end
Then, if you don't want to show the navbar in CarsController, do this:
class CarsController < ApplicationController
skip_before_filter :show_navbar, only: [list, of, actions]
end
where [list, of, actions] are the actions you don't want to show the navbar in.
Finally, change you layout to look like this:
<% if #show_navbar -%>
<%= render 'layouts/header' %>
<% end -%
Views
If you want to disable the header for whole controllers, first, move the header to app/views/application/ and change your render to:
<%= render partial: 'header' %>
Finally, in those controllers without navbar, add an empty _header.html.erb to app/views/controller_name.
For this option to work, you need at least Rails 3.1
I would set a different layout for those specific actions on specific controllers.

partial local only accessible using local_assigns, not exposed by name

I am passing two locals from a view ERB to a partial. Both locals are successfully passed in local_assigns. However, I am only able to use the FormBuilder via a local variable name in the partial. The other value is usable within my partial as local_assigns[:disable_edits], but not as disable_edits.
_form.html.erb
<div>
<%= f.fields_for :panels do |builder| %>
<%= render "panel_fields", :f => builder, :disable_edits => true %>
<% end %>
</div>
_panel_fields.html.erb
<div>
<p>
<%= local_assigns[:disable_edits] %>
</p>
<p>
<%#= disable_edits ? 'disable edits true' : 'disable edits false' %>
</p>
<p>
<%= local_assigns.keys %>
</p>
local_assigns[:disable_edits] results in "true" being displayed.
local_assigns.keys results in "[:f, :disable_edits, :panel_fields]" being displayed.
Uncommenting the ternary statement results in "undefined local variable or method `disable_edits' for #<#:0x4d58768>"
I am following what I understand is the latest suggested Rails syntax, but have tried manipulations using :partial=>, :locals=>, :as=>, etc. to no avail. I also do not think I've made this an optional argument in any way, so a lot of the information about testing with has_key vs. nil? isn't helping me. My understanding is everything in local_assigns should be exposed as in the partial as a local variable with the same name as the hash key.
I'm getting by for now using local_assigns[:disable_edits], but would like to understand what is happening and correct things so I can use more conventional syntax. Thanks!
try using
render :partial => "panel_fields", :locals => {:f => builder, :disable_edits => true }

Ruby on Rails: Custom Actions (Follow up)

This question is a follow up to this previous question: Ruby on Rails: Custom actions
As a follow up, what would be the syntax to use a custom action in a form_for? For my app, I have a partial called _invite_form.html.erb, and set the form to have a :url specification that I thought would link the form to the invite action on the Users controller:
<div id = "invite_form">
<h1>Invite</h1>
<%= form_for(invited, :url => invite_user_path) do |f| %>
<div class="field">
<%= f.text_field :email, :class => "inputform round", :placeholder => "email" %>
</div>
<div class="actions">
<%= f.submit "Invite", :class => "submit_button round" %>
</div>
<% end %>
</div>
This partial is called on certain pages, and this error is given:
"No route matches {:action=>"invite", :controller=>"users"}"
In my routes.rb file I have included the appropriate lines:
resources :users do
member do
get :invite
post :invite
end
end
Why is it that the route doesn't work? How do I change these files to make the form use the action "Invite" on the Users controller?
** Forgot to mention earlier: I defined invited in the Users helper: users_helper.rb:
module UsersHelper
def invited
#invited = User.new(params[:user])
end
end
As you don't have a persistent User just yet, make this a collection operation by:
Changing invite_user_path to invite_users_path in your controller
Changing member do to collection do in your routes
invite_user_path expects a user as an argument. Try invite_user_path(invited). You will also need to save the user before you can compute a path to it.
To experiment, go into rails console and see the difference between the following:
app.invite_user_path
app.invite_user_path(User.first)
app.invite_user_path(User.new)

Setup default CSS class for Rails' form builder helper methods

I'm looking for a generic way to apply some external CSS frameworks in a Rails application. These frameworks typically define a set of class names which should be used for certain HTML elements.
Consider jQuery UI. To achive a consistent form style, you would to something like this:
# in a view
<% form_for #foo do |f| %>
...
<%= f.text_field :bar, :class => ['ui-widget', 'ui-widget-content', 'ui-widget-container', 'ui-corner-all'] %>
or
<%= f.text_field :bar, :class => 'ui-widget ui-widget-content ui-widget-container ui-corner-all' %>
<% end %>
Doing this for each input field is not DRY at all.
Even a helper method like
# in application_helper.rb
def jquery_ui_classes
'ui-widget ui-widget-content ui-widget-container ui-corner-all'
end
# in a view
<%= f.text_field :bar, :class => jquery_ui_classes %>
or
# in application_helper.rb
def jquery_text_field(form_builder, method, opts = {})
ui = ['ui-widget', 'ui-widget-content', 'ui-widget-container', 'ui-corner-all']
klass = [opts.delete(:class), ui].flatten.compact
form_builder.text_field method opts.merge(:class => klass)
end
# in a view
<%= jquery_text_field f, :bar %>
does not look right (or more DRY), since you still would have to touch the generated form view...
Alternative ways might now be monkey-patching the InstanceTag class or hacking into the form_for helper.
Has anyone done this before?
By the way: I would avoid using jQuery (or Javascript in general) to apply the class attributes, since JS might be disabled or blocked or even delivered with delay and cause a flickering...
Cheers,
Dominik
https://github.com/phallstrom/form_helper_css
You can't specify the classes you want, but it will add reasonable class names to all inputs to allow you to easily target them (in all browsers).