I am creating list of forms say
Questions form
Answers form
Hints form
All these have different controller and view, question_controller , answers_controller, hints_controller.
Now I need to fetch all these views in tabbed UI in home page (say home_controller , home#index)
I tried render : partial ,render :template also with locals , I can't achieve.
It can be easily done by moving all the object to same controller ( home_controller , but i am not sure about this approach , since it will make home controller too complicated to manage ) , but I need to keep this in separate controllers (question_controller , answers_controller, hints_controller) and render it to same page. I am using client side validation, simple form gems.
Below is my question controller
class QuestionsController < ApplicationController
def index
#question = Question.new
#question_status = []
#question_mode = []
#question_type = []
#question_lookups = Lookup.where({:lookup_for => "question"})
#question_lookups.each do |lk|
case lk.lookup_type
when 'mode'
#question_mode << lk
when 'status'
#question_status << lk
else
#question_type << lk
end
end
#caa = Questioncaa.new
end
end
Question View ( with Simple form )
<%= simple_form_for #question, :validate => true do |q| %>
<%= q.input :question_info, :as => :ckeditor, :input_html => { :toolbar => 'Easy', :width => 750 } %>
<%= q.input :question_source %>
<%= q.input :is_mobile %>
<%= q.input :is_similar_question %>
<%= q.input :is_boss_question %>
<%= q.input :is_racing_question %>
<%= q.input :is_speed_question %>
<%= q.input :difficulty_level %>
<%= q.input :ideal_time %>
<%= q.input :lookups, :collection => #question_mode, :value_method => :id, :label_method => :lookup_value,:prompt => "Choose Mode", :label => :QuestionMode %>
<%= q.input :lookups, :collection => #question_status, :value_method => :id, :label_method => :lookup_value,:prompt => "Choose Status", :label => :QuestionStatus %>
<%= q.input :lookups, :collection => #question_type, :value_method => :id, :label_method => :lookup_value,:prompt => "Choose Type", :label => :QuestionType %>
<%= simple_fields_for #caa do |c| %>
<%= c.input :needs_hints %>
<%= c.input :needs_video_solution %>
<%= c.input :needs_tips_tricks %>
<%= c.input :needs_formulae %>
<%= c.input :needs_key_concepts %>
<% end %>
<%= q.button :submit %>
<% end %>
Home View
<div class="tab-content">
<div class="tab-pane active" id="learning_map">
<!-- I need to acheive this -->
<%= render :template => "learning_map/index" %>
</div>
<div class="tab-pane" id="questions">
<!-- I need to acheive this -->
<%= render :template => "questions/index", :collection => #question_mode %>
</div>
<div class="tab-pane" id="answers">.
<!-- I need to acheive this -->
<%= render :templates => "answers/index" %>
</div>
</div>
Pls advice me , it will be very helpful. Thanks for reading this.
You should change logic of your templates a little (here is example for 'question' view):
1) split your question template into 2 files:
- header with form declaration of simple_form_for
- _form.html.erb file with <%= fields_for #question do |q| %> and list of your questions fields like <%= q.input %>
2) add <%= render :partial => 'form' %> in your header file
3) use <%= render :partial => 'question\form' %> in your home view template
4) dont forget to initialize #question variable in home_controller.
Related
Suppose I have a form like below
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= uni_form.fields_for :apps do |builder| %>
<%= render 'app', uni_form: builder %>
<% end %>
<% end %>
and my app partial is
<div>
<%= uni_form.label :uni_id, "University" %>
<%= uni_form.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
</div>
Now I want the first form code without the loop. Something like this
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<% end %>
How can I do this?
Firstly, don't build your associated objects in your view - do it in your controller:
#app/controllers/unis_controller.rb
class UnisConstroller < ApplicationController
def new
#uni = Uni.new
3.times do
#uni.apps.build
end
end
end
Secondly, the fields_for method is your friend here.
You'll gain what you need by using the following:
#app/views/unis/new.html.erb
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<%= uni_form.fields_for :apps do |builder| %>
<%= builder.label :uni_id, "University" %>
<%= builder.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
<% end %>
<% end %>
fields_for takes your model's associated objects and automatically creates the fields you need. There is literally no need to "loop" - fields_for does it for you... if you set it up correctly.
The problem you have is you're building your associated objects at runtime, which is not only inefficient & against convention, but I think it will prevent the form_for from recognizing them (which is what allows fields_for to loop through them).
The above code should fix this for you.
I'm using 'rails-settings-cached' gem and I want to add ability of creating/updating settings in backend. Model has fields: 'var', 'value', etc... As form builder I'm using Formtastic-bootstrap.
When I doing f.input :value I get no implicit conversion of nil into String. I think that the reason is that 'value' is a keyword.
How can I solve my problem?
Thank you!
UPD:
<%= semantic_form_for [:admin, #setting], :html => {:class => "form-horizontal"} do |f| %>
<%= f.semantic_errors :var, :value%>
<%= f.inputs do %>
<%= f.input :var %>
<%= f.input :value, :as => :text %>
<% end %>
<%= f.actions :class => 'form-group' do %>
<div class="col-lg-offset-2 col-lg-8">
<%= f.action :submit %>
<%= f.action :cancel %>
</div>
<% end %>
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Passing only two variables between controller and view - best practice?
There is my action:
def list
#codes = Code.order("created_at")
#languages = Language.order('name').collect {|l| [l.name, l.coderay]}
end
There is my view(I removed some lines):
<% #codes.each do |code| %>
<div class="code">
<%= link_to code.title, :action => 'show', :id => code.id %>
<% if code.author %>
#<%= code.author %>
<% end %>
</div>
<% end %>
<%= render :partial => 'shared/error_messages', :locals => {:object => #code} %>
<%= form_for :code, :url => {:action => 'create' }, :html => {:multipart => true} do |f| %>
<%= f.text_field :title %><br />
<%= f.text_area :content %><br>
<%= f.select(:language, #languages, {:selected => 'text'}) %>
<%= f.text_field :author %><br>
<%= f.submit "Submit code" %>
<% end %>
There are 3 variables in it: #codes(list of posts), #code(current post, used in another action) and #languages.
My IDE writes:
At most two instance variables should be shared between controller and
view
This inspection warns if there are more than two instance
variables shared between a controller and a view. A controller should
only manage one instance variable, plus a second one for the
current_user variable.
Usually I share more variables between Controller and View(in PHP), sometimes 10+.
How it's done in Rails?
You can save an instance var by making languages a helper:
def languages
Language.order('name').collect {|l| [l.name, l.coderay]}
end
Its a guideline some developers follow some of the time.
But I would read up on Rails Routing a bit more. Understanding how Rails routing works should give you a better idea on how to structure your code.
http://guides.rubyonrails.org/routing.html
I modified your code a bit, not tested. But hopefully gives you some good ideas.
Controller:
def new
#code = Code.new
#codes = Code.order("created_at")
end
def create
#code = Code.new(params[:code])
if #code.save?
# Do your thing.
else
# render your :new action passing your #code variable
end
end
View:
<% #codes.each do |code| %>
<div class="code">
# Use Rails Routing - In console, type rake routes to get list of routes.
<%= link_to code.title, code_path(code.id) %> # example.
<% if code.author %>
<%= code.author %>
<% end %>
</div>
<% end %>
<%= render 'shared/error_messages', :object => #code %>
<%= form_for #code, :html => {:multipart => true} do |f| %>
<%= f.text_field :title %><br />
<%= f.text_area :content %><br>
# language_list = helper method.
<%= f.select(:language, language_list, {:selected => 'text'}) %>
<%= f.text_field :author %><br>
<%= f.submit "Submit code" %>
<% end %>
Here is a partial form _standards.html.erb we want to add to the view dynamically:
<p><%= f.association :standards, :collection => Standard.active_std.all(:order => 'name'), :label_method => :name, :value_method => :id :include_blank => true %></p>
Here is the view form itself _form_new.html.erb which calls _standards.html.erb:
<%= simple_form_for #rfq do |f| %>
<div id="std">
<%= render :partial => 'standards/standards', :collection => #rfq.standards, :locals => { :f => f } %>
</div>
<%= link_to_function("Add std", nil) do |page| %>
page.insert_html :bottom, 'std', :partial => 'standards/standards', :object => #rfq.standards.build
<% end %>
<%= f.button :submit, 'Save' %>
<% end %>
This solution did not work as link_to_function was not reacting to click by loading the _standards.html.erb. This solution seems out of date and does not work in rails 3.1.0. I am wondering if there is other solution to add dynamic content to the view page in rails 3.1.0. If you do, please don't hesitate to post. Thanks.
I know this answer is coming months after you need it but hopefully this helps someone else who stumbles across this question. Here is how you can dynamically add a selection box unobtrusively for your example.
_form_new.html.erb
<%= simple_form_for #rfq do |f| %>
<a id="add-selection-box" href="#">Add Selection Box</a>
<div id="std"></div>
<script type="text/javascript">
$(document).ready(function(){
$("#add-selection-box").click(function() {
$("#std").append("<%= escape_javascript(render(:partial => 'standards/standards', :collection => #rfq.standards, :locals => { :f => f })) %>");
});
});
</script>
<% end %>
Here is how you can do it using link_to_function
_form_new.html.erb
<%= simple_form_for #rfq do |f| %>
<%= add_selection_box "Add Selection Box", #rfq.standards, f %>
<div id="std"></div>
<% end %>
helpers/my_form_helper.rb
module MyFormHelper
def add_selection_box(name, collection, form)
page = %{
partial = "#{escape_javascript(render(:partial => "standards/standards", :collection => collection, :locals => { :f => form }))}";
$("#std").append(partial);
}
link_to_function name, page
end
end
'shared/subscription' %>
To call this partial view:
<% form_for(:subscription, :url => city_subscriptions_path(#city)) do |form| %>
<%= form.hidden_field :city_id, :value => #city.id %>
<%= form.text_field :email, :size => 30 %>
<%= form.submit "Email Me" %>
<% end %>
Since I am using this partial view on different places, how do I alter the caller so it will pass a hash for the form_for helper? So it would be like this when the helper is called:
<% form_for(:subscription, :url => city_subscriptions_path(#city), :html => {:id => 'main_input' }) do |form| %>
<%= form.hidden_field :city_id, :value => #city.id %>
<%= form.text_field :email, :size => 30 %>
<%= form.submit "Email Me" %>
<% end %>
<%= render :partial => "shared/subscription", :locals => {:foo => "bar", :foofoo => ["bar", "bar"]}
In your partial view, use them:
<%= foo #this outputs "bar" %>
<%= foofoo.to_s %>