Moving a rails form into a separate view - ruby-on-rails

I have a form in my rails 5 app that takes in User data and stores it in a mysql db.
Everything works great. However, I want to move this form into a separate view that does not correspond to its class name/model, controller name and view.
Can this be done by simply rendering the form into a separate view as a partial?
Any advice would be great.
Controller file:
class UserLeadsController < ApplicationController
def index
#user_lead = UserLead.all
end
def new
#user_lead = UserLead.new
#lead_reasons = LeadReason.all.map{ |r| [r.name, r.id] }
#lead_sources = LeadSource.all.map{ |s| [s.name, s.id] }
end
def create
#user_lead = UserLead.new(user_lead_params)
#user_lead.lead_reason_id = params[:lead_reason_id]
#user_lead.lead_source_id = params[:lead_source_id]
#user_lead.save
redirect_to user_leads_path
end
private
def user_lead_params
params.require(:user_lead).permit(:name, :businessname, :phone, :email, :amount)
end
end
Lets say this is UserLeadController, I want to place its form partial into a view inside of my HomeController? Can this be done?
This is the partial, it tells me #user_lead is nil or empty? I cant seem to see how it is?
<%= form_for #user_lead, url: user_leads_path, html: {class: 'col-12'}, remote: true do |f| %>
<div class="col-12 px-0 text-center">
<h4 class="fl-color-navy">Some heading here</h4>
</div>
<div class="col-12 progress-container-center">
<div class="col-12 progress-bar-block">
<div class="progress-bar">
<ol class="progress-steps">
<li class="progress-step step1 current-step" style="width: 0%;"> <span class="count highlight-index"></span></li>
<li class="progress-step step2 current-step" style="width: 100%;"> <span class="count"></span></li>
</ol>
</div>
</div>
</div> ....

Rendering the forms in a partial works fine. Submitting the form will direct the browser to the controller as normal if the view is correct (Presumably UserLeadsController#create, question didn't include the view code).
If things like #lead_reasons and #lead_sources are important to render the view, that is a little more tricky. Of course in simple cases the partial can just do it inline, you could also for example add a helper method that gets those and then renders the partial passing stuff to the locals param. e.g.
module ApplicationHelper
def user_leads_form
lead_reasons = LeadReason.all.map{ |r| [r.name, r.id] }
lead_sources = LeadSource.all.map{ |s| [s.name, s.id] }
render partial: "user_leads_form", locals: {lead_reasons: lead_reasons, lead_sources: lead_sources}
end
end
If you wanted it to go back to the previous page in some cases, e.g. for validation errors, you would need to add that, possibly by adding a parameter to the form, or inspecting the Referer request header (intentional misspelling!).
If you wanted it to not leave the page at all, then that is getting into client side scripting solutions.

Related

has_scope filter by cost feature [Ruby]

I need to set up a feature where the index page of freelancers can be filtered to only display based on a range on the attribute of price. This needs to be done from the user side, i was thinking two input boxes and a submit button.
How do I go about doing this? I checked out the has_scope gem, but I'm worried it's going to mess up my already defined order of freelancers, where they are ordered by the attribute featured (boolean). Essentially the order of the freelancers must stay the same, but then a filter must be added to that ordered object, to only show the freelancers in that price range.
There must be a way to do this but I'm very unsure. I'm going to do a bit of a code dump below, can someone point me in the right direction and show me how?
class HomeController < ApplicationController
before_action :set_freelancer, only: %i[ show edit update destroy ]
def index
#pagy, #freelancers = pagy(Freelancer.order(featured: :desc))
end
private
# Use callbacks to share common setup or constraints between actions.
def set_freelancer
#freelancer = Freelancer.find(params[:id])
end
end
My home controller
<% if user_signed_in?%>
<%== pagy_nav(#pagy)%>
<div class="d-flex flex-wrap justify-content flex-shrink-1 gap-3">
<%#freelancers.each do |freelancer| %>
<div class="card mb-3" style="max-width: 540px">
<div class="row g-0">
<div class="col-md-4">
<img src="https://i.pinimg.com/originals/57/f5/da/57f5da08bd8f52bc2d3e4ebadd67b642.jpg" class="img-fluid rounded-start" alt="6-logo">
</div>
<div class="col-md-8">
<div class="card-body">
<%= render freelancer %>
<%= link_to "Show this freelancer", freelancer, class: "btn btn-info" %>
</div>
</div>
</div>
<br/>
</div>
<%end%>
<% else %>
<h1>Please sign up, or sign in!</h1>
<%end%>
My webpage outputting each freelancer, ive also added my github itself below, im aware ive asked alot for help lately here but i am learning alot so i appreciate it
https://github.com/LCzoboriek/freelancer-assignment
(UPDATE)
So ive now added this code below to my home_controller.rb
def index
freelancers_scope = Freelancer.order(featured: :desc)
freelancers_scope = freelancers_scope.where("cost >= ?", params[:cost_lower_than]) if params[:cost_greater_than].present?
freelancers_scope = freelancers_scope.where("cost <= ?", params[:cost_greater_than]) if params[:cost_lower_than].present?
#pagy, #freelancers = pagy(freelancers_scope)
end
and this to my views, but its throwing an error saying undefined local variable or method `index' for #ActionView::Base:0x00000000013178. How do i point my form to that freelancers_scope part in my controller?
<%= form_for(index) do |f| %>
<%= f.input :cost_greater_than%>
<%= f.input :cost_lower_than%>
<%= submit_tag("Submit") %>
<% end %>
i was thinking two input boxs and a submit button.
this sounds absolutely fine
this is a very basic thing and you don't really need a gem for that, how about:
def index
freelancers_scope = Freelancer.order(featured: :desc)
freelancers_scope = freelancers_scope.where("cost >= ?", params[:cost_greater_than]) if params[:cost_greater_than].present?
freelancers_scope = freelancers_scope.where("cost <= ?", params[:cost_greater_than]) if params[:cost_lower_than].present?
#pagy, #freelancers = pagy(freelancers_scope)
end
if you really want a scope you could later define it in the Freelancer model so you wouldn't have to call where directly in the controller

I want my carousel to be appeared in index page only in rails application

I am new to rails and I want my carousel code to be seen in the index page only,please give a solution and below is my code :
<body>
<%= render 'layouts/navigation'%>
<%= render 'layouts/carousel' %>
<%= render 'layouts/messages'%>
<div class="container">
<div class="row">
<%= yield %>
<div class="col-md-8">
</div>
<div class="col-md-4">
</div>
</body>
Normally you'd want the move any code that's specific to a page out of the layout and into the template for the appropriate action.
However, in your case that piece of code looks embedded within the rest of the page skeleton so it could be hard to refactor it that way.
For this reason I'd suggest using conditional rendering by simply using a Boolean variable.
For example you could do:
<%= render 'layouts/carousel' if #render_carousel %>
And then you could just set the #render_carousel variable to true for any action that you'd want the carousel to appear in, e.g.:
def index
# rest of the code
#render_carousel = true
end

Rails nested form not working (child parameters not passed at all)

Model
`Buyer has_many :orders`
`Buyer accepts_nested_attributes_for :order`
`Order belongs_to :buyer`
View (buyers#new)
<%= form_for #buyer do |f| %>
<%= f.fields_for :orders do |o| %>
<div class="row">
<div class="col-xs-12">
<%= o.label "Select your meal" %>
</div>
</div>
<div class="row section">
<div class="col-xs-1"></div>
<% ["Pasta, pesto, & pea greens (veggie)",
"Mushroom cutlets & mornay sauce (veggie)",
"Italian breaded pork chop",
"Chicken kabobs with tzatziki",
"Asian-style sweet & sour beef"].each do |m| %>
<div class="col-xs-2 zero-padding">
<div class="col-xs-12">
<% image_tag "#{m}.jpg" %>
</div>
<div class="col-xs-12 text-center">
<%= o.radio_button :meal, m %>
<br>
<%= m %>
</div>
</div>
<% end %>
<div class="clearfix">
</div>
<% end %>
...
<% end %>
Controller (buyers)
def new
#buyer = Buyer.new
#buyer.orders.build
end
def create
# just to illustrate what i'm talking about, even the unsanitized parameters do not have orders_attributes
puts params
=> {"utf8"=>"✓", "buyer"=>{"first_stripe_token"=>"tok_16zExiKQ2oHmpkBLo9y45Cv3", "delivery_instructions"=>"random", "zipcode"=>"02110", "email"=>"test#example.com", "phone1"=>"123", "phone2"=>"456", "phone3"=>"0789", "agree_tos"=>"1"}, "controller"=>"buyers", "action"=>"create"}
end
def buyer_params
params.require(:buyer).permit(:first_stripe_token, :phone1, :phone2, :phone3, :zipcode, :delivery_instructions, :agree_tos, :email, orders_attributes: [:meal] )
end
Routes
match '/ondemand/create', to: 'buyers#create', via: :post, as: "buyers"
Some folks have asked questions about how to permit nested attributes via strong parameters. That's not my challenge. In my case, the nested attributes somehow are completely, as you can see above where I do a puts on the unsanitized parameters.
help!
If your f.fields_for block was correct and there was data in it, then the params would be correct even if strong params decides to block them. The fact that they don't show up in the params but other fields do show in the params makes me feel like the problem is in your f.fields_for block.
Figured out the answer... but a little worried since this seems like such a common problem and I haven't seen a mention of it anywhere. So if I'm doing something totally wrong... please clue me in.
What happened is that the orders_attributes were not being passed on the SECOND try of a failed submission (I'm running rspec tests here). And the reason they weren't being passed is because they were nonexistent on the form. Here's why:
def new
#buyer = Buyer.new
#buyer.orders.build
end
In the new action, the form creates fields for both buyer and order because both have been initialized. But my original create action looked like this:
def create
#buyer = Buyer.new(buyer_params)
...
if #buyer.save
redirect_to '/'
else
render 'new'
end
end
In other words, if everything went well, and the buyer_params built out valid buyer and order, great! But if some kind of error happened, and the page re-rendered, there is no order object to build the form fields for!
As a result, the answer:
def create
#buyer = Buyer.new(buyer_params)
#buyer.orders.first_or_intialize
if #buyer.save
...
end
The result is this:
If there are no errors the first line creates both buyer and order and the second line is kind of a moot point since it will just call the just-created order (in my case even though I've written it as a has_many, realistically a buyer only has one order; even if that weren't the case, I'm not using the order object to do anything, so the second line does no harm)
If there are errors then the second line instantiates an order object so that when the page is re-rendered, there is an order object to build fields for

Moving rails from to from _form.html.erb to application.html.erb

I have most of the functionality done for a site. Now I am trying to make it look nice. I have a _form.html.erb that works great.
<%= form_for(#card) do |f| %>
<% if #card.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#card.errors.count, "error") %> prohibited this card from being saved:</h2>
<ul>
<% #card.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :event %><br />
<%= f.text_field :event %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Files
view
- cards
-- new.html.erb
-- index.html.erb
-- show.html.erb
- layouts
-- application.html.erb
- pages
-- index.html.erb
I make a call for the form from new.html.erb and it works sends it to show.html.erb, just as I want. I'm using bootstrap and decided to make use of the nav bar. I have placed the nav bar code into the application.html.erb. It works just fine, well kind of. I want what would normally be a search function to be the add a new card.
When I add the form call it does not work, when I add it directly to the application page it does not work. I'm not sure, I have spent hours on this. I got it to work only on the show.html.erb page, both index pages would error out. I honestly don't remember how I did this though.
I'm trying to learn by doing, but I am stuck and need some help.
Thank you,
Ian
I guess that when you say that its working in your new.html.erb you have a new action inside your cards_controller, and inside this action you have something like: #card = Card.new
Well, if you want to put this form in another view, like in the application.html.erb you need to set first your #card variable, so you can do something like:
# application_controller:
before_filter :new_card
def new_card
#card = Card.new
end
be aware that all the controller that inherits from application controller will set this #card variable
#instance_variable
The underlying problem here is that you're calling a partial - by design, these are meant to give you the ability to call the functionality the file contains anywhere in your application
The problem you have is you're referencing an #instance_variable directly in your partial.
This isn't normally an issue - if you're using partials like you were originally (to modularize views), it should be okay. The problems arise when you try and use the partials in a more generalized way, as you are doing now:
#app/views/controller/_form.html.erb
<%= form_for(#card) do |f| %>
This relies on the #card instance variable being made available, which won't be if you're loading the partial in any other controller than the cards_controller.
--
Fix
The way to fix this is to either populate the #card instance variable in the application controller (as described by edymerchk), or to pass the raw value through the locals hash of the partial call:
This will allow you to use the card local variable in your partial:
#app/views/controller/_form.html.erb
<%= form_for card do |f| %>
-
Alternatively, you could also set the #card instance variable, as recommended in another answer:
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
before_action :set_card
private
def set_card
#card = Card.new
end
end

Want to define a section in my application_layout, but override it in a particular case, possible?

Say my application layout is like has:
<div id=container>
<div id=content>
<%= yield %>
</div>
</div id=sidebar>
<div id=top></div>
<div id=bottom></div>
</div>
Now on the about page, I want to hide the sidebar section, how could I do this?
on the contact page, I want to override the contents of the sidebar.bottom part? is that possible?
In your application_controller.rb
before_filter :enable_sidebar
def enable_sidebar
#show_sidebar = true
end
In your about action:
def about
#show_sidebar = false
end
In your layout
<% if #show_sidebar %>
<div id="sidebar">
...
</div>
<% end %>
Use a similar approach for your contact page, or use a symbol value rather than a boolean to select different sidebar variations. The idea is the same: set a default, and then set some controller instance variables to alter depending on your needs on a per-action basis.

Resources