I'm having the following error while trying to pass locals to the partial:
undefined method `country_code' for nil:NilClass
This is what my code looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Trial</title>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<script type="text/javascript">
$(document).ready(function() {
$('select#order_country_code').change(function(){select_wrapper = $('#order_state_code_wrapper');
$('select', select_wrapper).attr('disabled', true);
country_code = $(this).val();
url = "subregion_options?parent_region=#{country_code}";
$('#order_state_code_wrapper').load(url);
});
});
</script>
</head>
<body>
<%= form_for(:order) do |f| %>
<div class="field">
<%= f.label :country_code %><br />
<%= f.country_select :country_code, priority: %w(US CA), prompt: 'Please select a country' %>
<%= f.label :state_code %><br />
<%= render partial: 'subregion_select', locals: {parent_region: f.object.country_code} %>
</div>
<% end %>
</body>
</html>
Partial:
<div id="order_state_code_wrapper">
<% parent_region ||= params[:parent_region] %>
<% country = Carmen::Country.coded(parent_region) %>
<% if country.nil? %>
<em>Please select a country above</em>
<% elsif country.subregions? %>
<%= subregion_select(:order, :state_code, parent_region) %>
<% else %>
<%= text_field(:order, :state_code) %>
<% end %>
</div>
Controller:
class OrdersController < ApplicationController
layout false
def index
end
def subregion_options
render partial: 'subregion_select'
end
end
Routes:
Rails.application.routes.draw do
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'access#index'
match ':controller(/:action(/:id))', :via => [:get, :post]
get 'subregion_options' => 'orders#subregion_options'
end
Thank you very much for your help :)
I think you need to add this in appropriate action in your controller :
#order = Order.new
and in view, instead
form_for(:order)
put
form_for(#order)
Add to your config/routes.rb following:
resources :orders, only: [:index]
finally it works after your advice.I also had this wrong and it was not passing parameters in the url :
url = "subregion_options?parent_region=#{country_code}";
I dont know in cofeescript but in javascript the correct way is like this :
url = "subregion_options?parent_region="+country_code;
Related
I have a problem. In my Rails app, I am trying to load a list of data using given select-option elements. When I hit submit, I am getting an error that the create method doesn't exist in my controller (which is true). I am new with this turbo-rails package, but this is what I got so far:
index.html.erb
<!DOCTYPE html>
<html>
<head>
<%= stylesheet_link_tag 'users/main', 'data-turbolinks-track': 'reload' %>
<%= csrf_meta_tags %>
</head>
<body>
<main>
<div class="grid">
<div class="users">
<div class="filters">
<form action="/users" method="POST">
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
<%= render partial: "shared/select", locals: {
placeholder: 'Gender',
width: '90px',
options: $genders,
classes: 'filter',
name: 'gender'
} %>
<button type="submit">submit</button>
</form>
</div>
<div id="user-data-list">
<%= render partial: "users/user_list", locals: {
users: #users
} %>
</div>
</div>
</div>
</main>
</body>
</html>
users.controller.rb
class UsersController < ApplicationController
before_action :require_user
USERS_PER_PAGE = 15
def index
#users = User.limit(USERS_PER_PAGE).order(:creation_date).reverse_order
end
def load
gender = if params[:gender] then params[:gender] else '' end
#users = User.limit(USERS_PER_PAGE).where(
"gender LIKE ?", "%" + gender + "%"
).order(:creation_date).reverse_order
respond_to do |format|
format.turbo_stream
format.html { redirect_to users_url() }
end
end
end
load.turbo_stream.erb
<%= turbo_stream.replace "user-data-list" do %>
<%= render partial: "users/user_list", locals: {
users: #users
} %>
<% end %>
routes.rb
Rails.application.routes.draw do
# System check
get '/health', to: 'application#health'
get '/users' => "users#index"
post '/users' => "users#load"
resources :users
post '/login' => 'auth#login'
get '/logout' => 'auth#logout'
end
_select.html.erb
<!DOCTYPE html>
<html>
<head>
<%= stylesheet_link_tag 'components/select', media: 'all', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<select
style="<%= 'width: ' + width + ';' if width %>"
<% if defined?(id) %>
id="<%= id %>"
<% end %>
<% if defined?(classes) %>
class="<%= classes %>"
<% end %>
<% if defined?(name) %>
name="<%= name %>"
<% end %>
<% if defined?(required) %>
required
<% end %>
>
<option
value=""
disabled
selected
hidden
>
<%= placeholder %>
</option>
<% options.each do |option| %>
<option><%= option %></option>
<% end %>
</select>
</body>
</html>
But when I run this code and hit the submit button I get the following error:
I don't have a create method in my controller, because there is no possible option to create a user. I have a custom load method, and I can't seem to figure out why it is trying to call the create method. Can someone explain this to me?
Routes have priority in the order they are declared.
resources :users already declares a POST /users route. While you could fix it by moving your strange route up you don't actually even need this in the first place.
What you're doing looks like you're simply adding a bunch of filters to a resource. You can do that by just sending a GET request to the collection path (the index) and having it use the optional query string parameters to apply conditions.
Rails.application.routes.draw do
# System check
get '/health', to: 'application#health'
# Only declare the routes you're actually using!
resources :users, only: [:index]
post '/login' => 'auth#login'
get '/logout' => 'auth#logout'
end
<%= form_with(url: users_path, method: :get, data: { turbo_frame: "user-data-list" }) do |form| %>
<%= render partial: "shared/select", locals: {
placeholder: 'Gender',
width: '90px',
# why is this a global?
options: $genders,
classes: 'filter',
name: 'gender',
form: form # pass the form builder along
} %>
<%= form.submit %>
<% end %>
# /app/users/index.turbo_stream.erb
<%= turbo_stream.replace "user-data-list" do %>
<%= render partial: "users/user_list", locals: {
users: #users
} %>
<% end %>
class UsersController < ApplicationController
before_action :require_user
USERS_PER_PAGE = 15
def index
#users = User.limit(USERS_PER_PAGE)
.order(:creation_date: :desc)
if params[:gender]
# and why is this pattern matching?
#users.where("gender LIKE ?", "%#{gender}%")
end
respond_to do |format|
format.turbo_stream
format.html
end
end
end
Conceptually performing a search, adding pagination or any other kinds of filters via query strings parameters are idempotent actions as its not creating or altering anything and the resource will look the same for any visitor using the same URI (in theory at least).
You should thus use GET and not POST which lets the request be saved in the browsers history - be cached, and be directly linkable.
I'm fairly new to rails and didin't find a soloution after a lot of research...
I want to build a simple data abstaraction test app. I have a text field and a submit button and I want to do something with the input (like ie. .upcase ) and then print it out. On submit, I get a routing error, though.
What am I doing wrong?
application.html.erb
<body>
<%= form_tag("parse_input", method: "post") do %>
<%= text_field(:ans, :field) %>
<%= submit_tag("submit" %>
<% end %>
FormControllerController.rb
class FormControllerController < ApplicationController
def parse_input
params[:ans].each do |value|
puts value
end
end
end
routes.rb
Rails.application.routes.draw do
...
root :to => 'application#home'
get "application" => "form_controller_controller"
end
I don't want to use a DB btw.
Try below code:
routes.rb
Rails.application.routes.draw do
...
root :to => 'application#home'
post "parse_input" => "form_controller_controller#parse_input"
end
application.html.erb
<body>
<%= form_tag("/parse_input") do %>
<%= text_field(:ans, :field) %>
<%= submit_tag("submit") %>
<% end %>
Rails Newbie. Be gentle. If I need to show more stuff I'll do it.
Trying to insert a newsletter signup block above my footer on a project but didn't make it a partial in the layouts set up.
I have the yield outputting an index from a blog.
Right now it's just saying "false" on my local host.
Is it possible to have multiple yields to different indexes?
Is it possible to insert another page into a layout page?
application.html.erb
<div id="blog">
<%= yield %>
</div>
<div>
<%= content_for?(:newsletter) ? yield(:newsletter) : yield %>
</div>
<div>
<%= render 'layouts/footer' %>
</div>
newsletter.html.erb
<% content_for :newsletter do %>
<h1>Get My Awesome News Letter</h1>
<p>Give me your email and keep up to date on my cat's thoughts.</p>
<%= form_tag('/emailapi/subscribe', method: "post", id: "subscribe", remote: "true") do -%>
<%= email_field(:email, :address, {id: "email", placeholder: "email address"}) %>
<%= submit_tag("Sign me up!") %>
<% end %>
emailapi_controller.rb
class EmailapiController < ApplicationController
def newsletter
render params[:newsletter]
end
def subscribe
gb = Gibbon::Request.new
gb.lists.subscribe({
:id => ENV["MAILCHIMP_LIST_ID"],
:email => {:email => params[:email][:address]}
})
end
end
routes.rb
root to: 'posts#index'
get "/:newsletter" => 'emailapi#newsletter'
post 'emailapi/subscribe' => 'emailapi#subscribe'
You shouldn't need this conditional test:
content_for?(:newsletter) ? yield(:newsletter) : yield
try just:
<%= content_for :newsletter %>
Here's the doc on content_for:
http://apidock.com/rails/v4.2.1/ActionView/Helpers/CaptureHelper/content_for
Ie only show the newsletter if newsletter is present.
The extra yield (if newsletter-content is not present) is repeated from the blog-section above.
You probably shouldn't have duplicate plain yields just the one... everything else should have a name (eg :newsletter)
Also - you seem to be missing an <% end %> in newsletter.html.erb
You should be able to just use another render block. I'm not sure where your newsletter.html.erb lives, but if, for example it lived in a folder such as includes/ you could do something like:
<%= render 'includes/newsletter' %>
I want to flash a notice/error if the email is/isn't saved, without using a redirect. I am using Rails 4 for the project, and here is my code:
layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>FarFlung Jobs</title>
<!-- /.You can include style.css into stylesheet_link_tag too. If you do so, dont forget to add style.css in asset.rb -->
<%= stylesheet_link_tag 'application', 'jobs', media: 'all' %>
<%= javascript_include_tag 'application' %>
<%= javascript_include_tag 'config', 'sharebutton', 'jobsalert', 'modernizr'%>
<%= render 'payola/transactions/stripe_header' %>
<%= csrf_meta_tags %>
</head>
<body>
<%= render 'shared/navbar' %>
<div>
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, class: 'alert alert-info' %>
<% end %>
</div>
<%= yield %>
<%= render 'shared/footer' %>
</body>
</html>
users/new.html.erb
<section class="cd-form-wrapper cd-container">
<div class="column panel panel-default">
<div class="cd-filter"><h4>SUBSCRIBE FOR JOBS ALERT</h4></div>
<%= simple_form_for User.new do |f| %>
<%= f.input :email, label: false, :placeholder => 'Enter your email address...', :input_html => { :class => 'newsletter-form-field-styling' } %>
<%= f.button :submit, 'SUBMIT', :class => 'btn-block newsletter-form-styling btn-primary submit' %>
<% end %>
</div>
</section>
users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(secure_params)
if #user.valid?
#user.save
flash.now[:notice] = "#{#user.email} is signed up for Jobs Alert."
else
flash.now[:alert] = 'Error Subscribing!'
end
end
private
def secure_params
params.require(:user).permit(:email)
end
end
How do I get the Rails flash message working to appear on my subscription form without redirecting the page?
You can submit your form passing remote: true. It'll (as you can expect) remotely submit your form, so you can return an json an render the expected flash. Ex:
Your form:
simple_form_for User.new, remote: true, class: 'your-form' do
<your code>
Your controller
def create
#user = User.new(secure_params)
if #user.save
render json: { status: 'success', message: "#{#user.email} is signed up for Jobs Alert." }
else
render json: { status: 'failure', message: 'Error Subscribing!' }
end
end
Your JS (perhaps new.js - and be sure to include it in your view)
// you can specify your bind container, here I just used the document
$(document).on('ajax:success', '.your-form', function(e, data) {
if(data.status == 'success'){
showSuccessFlash(data);
}else{
showErrorFlash(data);
}
});
Explaining:
Using the remote: true, your page will wait for an ajax answer, which you can get listening to ajax:success (or other bindings).
Then, it will receive the json and will store in the data variable. So you will get the data.status and the data.message, which you can show to your user as a feedback.
More infor about the remote: true http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#form-for
More info about the JS callbacks https://github.com/rails/jquery-ujs/wiki/ajax
You can use a gem like Gon that will monitor variables and handle all of the Ajax for you automatically.
It's very easy to setup, and you can have it perform the update at whatever time interval you choose. If you're simply transporting a variable, this will save you some Ajax coding. And it will update your page without any kind of redirect, so it does exactly what you're looking for.
However, one other tweak I figured out to solve this problem is with/without redirect is using application helper to make your Flash Global and used on any View of your choice.
Move your Flash Message to Partials e.g.
shared/_flash_messages.html.erb
<div class="text-center">
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, class: 'alert alert-info' %>
<% end %>
</div>
Define custom helper method for your flash messages using the exact same old rails method use to have. Such that the method renders our partials and the object will be parsed along to your partials.
helpers/application_helper.rb
module ApplicationHelper
def flash_messages_for(object)
render(:partial => 'shared/flash_messages', :locals => {:object => object})
end
end
Inside my View, you can call it with erb tags and call the form object on it such as <%= flash_messages_for(User.new) %> or <%= flash_messages_for(#user) %>. See code below:
users/new.html.erb
<section class="cd-form-wrapper cd-container">
<div class="column panel panel-default">
<%= flash_messages_for(User.new) %>
<div class="cd-filter"><h4>SUBSCRIBE FOR JOBS ALERT</h4></div>
<%= simple_form_for(User.new) do |f| %>
<%= f.input :email, label: false, :placeholder => 'Enter your email address...', :input_html => { :class => 'newsletter-form-field-styling' } %>
<%= f.button :submit, 'SUBMIT', :class => 'btn-block newsletter-form-styling btn-primary submit' %>
<% end %>
</div>
With this, my error messages are flashed on any view or form I call <%= flash_messages_for(User.new) %> on.
You can refer to Kevin Skoglund formerrors Ruby on Rails Tutorials on Lynda.com Click to watch
I am trying to ensure that each job has the correct link when a user clicks on it.
The issue I am having is that I keep getting the error Couldn't find job without an ID.
In my view I have the following code:
<% #jobs.group_by{|x| x.created_at.strftime("%d %b. %Y")}.each do |date,jobs_on_that_date| %>
<section class="date"><%= date %></section>
<section id="top-job">
<% jobs_on_that_date.each do |job| %>
<section id="job-wrapper">
<%= link_to url_with_protocol(#link.job_url), :target => '_blank' do %>
<section id="job">
<%= job.title %> - <%= job.company %>
<%= job.salary %>
<%= job.location %>
<%= job.job_type %>
</section>
</section>
<% end %>
<% end %>
</section>
<% end %>
In my controller I am creating an object called #link as follows:
def index
#user = current_user
#jobs = Job.where('created_at > ?', 30.days.ago).reverse
#link = Job.find(params[:id])
end
Finally I have the following Routes setup.
JobappV2::Application.routes.draw do
devise_for :users
resources :jobs
resources :users do
resources :jobs
end
root :to => 'jobs#index'
end
If I use #link = Job.find(2) this works but every job ends up with the link input by the job with id 2.
Thanks in advance for any help!
what is params[:id]?
I suspect that if you do raise params[:id].inspect in your controller, you will find it's nil. Besides, what's the point in creating #link? just put job.job_url in your view instead of #link.job_url