I am brushing up on my rails. I have a dead simple form. views -> genalg -> index.html.erb
<h1>Genalg#index</h1>
<p>Find me in app/views/genalg/index.html.erb</p>
<%= form_with url: "/calculate" do |form| %>
<%= form.text_field :query %>
<%= form.submit "calculate" %>
<% end %>
<% unless #query.nil? %>
<p><%=#query%></p>
<% end %>
I have a controller under controllers -> genalg_controller.rb
class GenalgController < ApplicationController
def index
#query = "biznass"
end
def calculate
puts params
#query = (params[:query].to_i * 2).to_s
render :index
end
end
In routes.rb:
Rails.application.routes.draw do
get 'genalg/index'
post '/calculate', to: 'genalg#index' , as: 'index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
How, when I fill the from text :query and hit submit, can I get the text denoted at the very end of my view to display the value I put in times 2 (per the calculate function)? Seems like it should be easy but clearly I have forgotten some basic tenant of how forms and form submission works.
Change the render to redirect_to and pass params like this
def calculate
puts params
#query = (params[:query].to_i * 2).to_s
redirect_to index_path(query: #query)
end
<% unless params[:query].blank? %>
<p><%=#query%></p>
<% end %>
Looking at your routes file, you are calling index action on submitting a post request for calculate so its always returns #query value from the index method i.e. biznass
If you want to calculate #query using params and use index action for that with same routes defined, you have to update index method
def index
if params[:query]
puts params
#query = (params[:query].to_i * 2).to_s
else
#query = 'biznass'
end
OR you can change route and controller code
Rails.application.routes.draw do
get 'genalg/index'
post 'genalg/calculate'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
class GenalgController < ApplicationController
def index
#query = params[:query] || "biznass"
end
def calculate
puts params
#query = (params[:query].to_i * 2).to_s
redirect_to index_path(query: #query)
end
end
I suggest use resources in your routes.rb instead doing it like that, it will be far more concise, scaleable and you can use url helper method. you can run rake routes in your terminal to see detail of routes, like helper method's name, path, http verb, and which controller's method a path is using.
resources :genalg, controller: :genalg, only: [:index] do
collection do
post :calculate
end
end
in this instance of def calculate, If you have method with http verb POST and it supposed to response with success status, most of the time you need to redirect it instead of rendering it, because in case when user refresh or copy url after calculate, the page will not be found as calculate have POST http verb.
so you have to change render to redirect_to and pass params :query, so every time user refresh the page after calculate, :query will be persisted. even if you want to store :query in database this is still applicable. also, in here you can see we use helper method to redirect to index page by using genalg_index_path
def calculate
puts params
query = (params[:query].to_i * 2).to_s
redirect_to genalg_index_path(query: query)
end
then in index you can check whether params query is empty or not
def index
#query = params[:query] || 'biznass'
end
And in view as you can see we use helper method again to get calculate path, and we don't need #query condition as it never nil
<h1>Genalg#index</h1>
<p>Find me in app/views/genalg/index.html.erb</p>
<%= form_with url: genalg_calculate_path do |form| %>
<%= form.text_field :query %>
<%= form.submit 'calculate' %>
<% end %>
<p><%=#query%></p>
Related
I am trying to display only the rows that belong to certain states in my application. I can do it the long way in Javascript, but I would prefer to better understand Rails and queries in the controller. I want to take the users to another page and then show them only that the companies in that state. It would be great to not have to link them to another page. Does anyone know how to do this?
Here is what I have in my controller
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(params[:state])
end
My route
get '/vendors/:state', to: 'collectives#vendors'
Then I use the stereotypical method to print a table in a html.erb file.
<% #vendors.each do |company| %>
<tr>
<td><%= company.name %></td>
<td><%= company.state %></td>
etc...
Should your controller code change the where as follows:
def vendors
#vendors = Collective.where(sort: 'Vendor').all
#vendors = #vendors.where(state: params[:state])
end
or better:
def vendors
#vendors = Collective.where(sort: 'Vendor', state: params[:state])
end
Using sessions instead of url params.
This is more or less what you can do, sorry if it is not completly working for your case, just to give an idea.
# view collectives/index (or whatever you have)
<%= form_tag (controller: :collectives, action: :set_status_filter, method: :post) do %>
<%= select_tag(:session_status_filter, options_for_select(#your_list_of_options_for_the_filter)) %>
<%= submit_tag "Set filter" %>
<% end %>
# collectives controller
def index # or whatever, this is the page containing the form and the list to show
#vendors = Collective.where(sort: 'Vendor').all
if session[:session_status_filter] == # etcetera
then #vendors = #vendors.where(state: session[:session_status_filter]) # for example
else # another option just in case, etcetera
end
end
def set_status_filter # this action is called by the form
session[:session_status_filter] = params[:session_status_filter]
respond_to do |format|
format.html { redirect_to *** the view where the form is placed ***, notice: 'the filter is set to: ....' + session[:session_status_filter] } # after the session variable is set the redirects goes to index which uses the session to filter records
end
end
params[:session_status_filter] is passed by the form to collectives#set_status_filter. The value is used to set the session variables. After that the action collectives#set_status_filter redirects to the index, or whatever page you placed the form and the list to show.
I have something like that in my controller:
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
I want to use search method in index action but I don't want to remove my #votes variable from index. If I use before_action, it calls method before the action so #votes doesn't change. Is it possible to call search method after my votes variable or ignore the variable without removing.
I normally go with this method when I'm looking to build a simple search:
http://railscasts.com/episodes/37-simple-search-form
Create a method in your vote.rb file:
class Vote
def self.search(search)
if search
self.where(:all, conditions: ['name LIKE ?', "%#{search}%"])
else
self.where(:all)
end
end
end
This means when you do Vote.search('term'), you'll bring up any records with a similair name. Replace name for whatever term you're searching for (i.e. title or category).
If there is no search term entered this method simply returns every instance. This means you can leave your controller looking like this:
def index
#votes = Vote.search(params[:search])
end
Finally the view for this would be something like:
<% form_tag votes_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
This will send a get request to the votes_path (the index action on your controller), with the search term parameter. If one is entered the search will return the relevant instances, and if not it will return all.
Try
class TempController < ApplicationController
after_action :search
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
end
I'm trying to make simple app. I input my first name and last name to simple <%= form_for #data do |f| %> rails form and after submitting it, app should render simple text like this. My first name is <%= data.first_name %> and my last name is <%= data.last_name %>. I don't know why but my app is saying this error:
undefined local variable or method `data' for
It's probably saying it because no params are passed to view.
Here is my code.
routes.rb
resources :data, only: [:new, :create, :index]
data_controller.rb
class DataController < ApplicationController
def new
#data = Data.new
end
def index
end
def create
#data = Data.new(data_params)
if #data.valid?
redirect_to #data
else
render :new
end
end
private
def data_params
params.require(:data).permit(:first_name, :second_name)
end
end
/views/data/new.html.erb
<%= form_for #data do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :second_name %>
<%= f.text_field :second_name %>
<%= f.submit 'Continue', class: 'button' %>
<% end %>
/views/data/index.html.erb
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= data.first_name %>.</p>
<p>And my second name is: <%= data.second_name %>.</p>
/models/data.rb
class Data
include ActiveModel::Model
attr_accessor :first_name, :second_name
validates :first_name, :second_name, presence: true
end
Please help to find out why params are not passing to next page. Thanks anyways :D
Your view should look like this:
<h2>Coolest app ever :D</h2>
<p>My first name is: <%= #data.first_name %>.</p>
<p>And my second name is: <%= #data.second_name %>.</p>
Also, I would suggest that calling a model something generic like Data is not a very Rails-y approach. Generally, domain models correspond to real-world things like User and Article, which are easy to understand and relate to. It'll get confusing quite fast if you use need to make another model and want to call it Data2 or something :)
Edit:
Since you specified that you do not wish to use the database, I would recommend passing in the object params through the redirect:
redirect_to(data_path(data: #data))
and in your controller's index method:
def index
#data = Data.new(params[:data])
end
Now your view should render properly, since you're passing the in-memory #data object attributes as params within the redirect. You then recreate this object in the index page or wherever you wish to redirect to.
To expand on Matt's answer, the reason you're getting NilClass errors is because:
You're redirecting to a data#show action when no show action has been enabled within your routes file. Since you've set your views up for the index, I'm assuming you want to redirect there when the #data object has been verified as valid:
redirect_to data_path
However I would recommend you follow Rails conventions and specify the data#show route within your routes.rb:
resources :data, only: [:index, :new, :create, :show]
and in your data_controller.rb:
def show
#data = Data.find(params[:id])
end
Another problem is that you're not actually saving the #data object upon creating it. The new method populates the attributes, and valid? runs all the validations within the specified context of your defined model and returns true if no errors are found, false otherwise. You want to do something like:
def create
#data = Data.new(data_params)
if #data.save
redirect_to data_path
else
render :new
end
end
Using save attempts to save the record to the database, and runs a validation check anyways - if validation fails the save command will return false, the record will not be saved, and the new template will be re-rendered. If it is saved properly, the controller will redirect to the index page, where you can call upon the particular data object you want and display it within your view.
I'm working on a little stock market app where the users can lookup company stock info based on the ticker symbol. After the user has posted the :symbol param in the search field, they should be redirected to the appropriate "company" page (like Wall Street Journal, Yahoo Finance, Google Finance, etc). I'm currently able to manually type in the route with the symbol and everything works good. For example, localhost:9292/company/GOOG. I'm a total noob, so any help would be greatly appreciated. Thanks!
I currently have this in my view:
<%== search_field_tag(:symbol, "Enter symbol") %>
<%== submit_tag ("Search") %>
This is in my routes:
get "/company/:symbol" => "main#company"
post "/company/:symbol" => "main#company_post"
EDIT: I'm using the MarketBeat gem to pull in the data, but I also have a Company table where I have columns symbol and name. Here is my controller:
class MainController < ApplicationController
def index
render :index and return
end
def company
#name = MarketBeat.company params["symbol"]
#symbol = MarketBeat.symbol params["symbol"]
#price = MarketBeat.last_trade_real_time params["symbol"]
#change = MarketBeat.change_and_percent_change params["symbol"]
#volume = MarketBeat.volume params["symbol"]
#days_range = MarketBeat.days_range params["symbol"]
#eps = MarketBeat.earnings_to_share params["symbol"]
#pe = MarketBeat.pe_ratio params["symbol"]
#stock_exchange = MarketBeat.stock_exchange params["symbol"]
market_cap = MarketBeat.market_capitalization params["symbol"]
# #market_cap is rounded to billions
#market_cap = market_cap.to_i / 1000
render :company and return
end
In your main#company_post method, put the following:
redirect_to "/company/#{params[:symbol]}"
So the routes should be:
get "/company/:symbol" => "main#company"
post "/company" => "main#company_post"
The controller:
def company_post
redirect_to "/company/#{params[:symbol]}"
end
The view:
<%= form_tag("/company", method: :post) do %>
<%= search_field_tag(:symbol, "Enter symbol") %>
<%= submit_tag ("Search") %>
<% end %>
At the end of your #company controller method you probably will do something like this
render "#{params[:symbol]}"
or
render partial: "#{params[:symbol]}"
along with have a template file with the same name of the company, like google.html.erb
Give it a try!
I make simple search system that looks almost like your task
Full example
routes.rb
post 'search' => 'vids#prepare_search', as: :prepare_search_vids
get 'search(/*query)' => 'vids#search', as: :search_vids
vids_controller.rb
# GET /search(/*query)
def search
#results = Title.search params[:query] if search_query?
if #results.count == 1
flash[:notice] = I18n.t 'vids.search.signle_result'
redirect_to #results[0].vid
end
#query = params[:query]
end
# POST /search
def prepare_search
query = params[:q] ? params[:q] : ''
redirect_to search_vids_path(query)
end
private
def search_query?
params[:query] and !params[:query].blank?
end
Also in your situation I recommend use asteriks instead of colon in routes http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments
Route
resources :cars do
collection do
get :f01a
end
end
Controller
class CarsController < ApplicationController
def f01a
#user = User.find(params[:id])
#count = Count.find_by_user_id(#user)
#count.increment!(:f02)
redirect_to #user
end
end
View
<%= button_to "add f01", f01a_cars_path %>
I can't get this to work. I need to execute this code from a button.
button_to sends a POST request, but your routing is setup to only accept GET requests. You should change it to:
resources :cars do
collection do
post :f01a
end
end
Since you're using params[:id] in your action, but not sending it in at all, you'll need to pass it in your button_to:
<%= button_to "add f01", f01a_cars_path(:id => something)
(Replace something with whatever ID you want to pass.)