Ruby on Rails - Show method for a parsed JSON result - ruby-on-rails

I am building a seemingly simple website for a visitor to get a status update on a selected data piece. The data comes from an external API. The gist of it is this: the visitor sees a list of the data names, clicks one, and is redirected to a partial with status update, either True or False.
My index method works very well, and iterates through the data names perfectly. I believe my routing (using the friendly_id gem) should work fine. However, I cannot figure out how to properly set up the show method.
Here is my code thus far:
Controller:
class DataController < ApplicationController
include HTTParty
attr_accessor :name, :status
def index
#response = HTTParty.get("api_url").parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "index.html.erb" }
end
end
def show
#response = HTTParty.get('api_url').parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result, :include => { :data => { :only => [:name, :status]}}) }
format.html { render "show.html.erb" }
end
#name = #response.find(params[:name])
end
end
View:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
Routes:
Rails.application.routes.draw do
root 'data#index'
get '/:name' => 'data#show', as: "name"
end
All of this together brings up the following error:
ActionController::UrlGenerationError in Data#index
Showing /app/views/layouts/_header.html.erb where line #11 raised:
No route matches {:action=>"show", :controller=>"data", :name=>nil} missing required keys: [:name]
What I am trying to accomplish is to be able to route each iterated link as 'root/{data name}', pulling {data name} from the JSON result as a parameter, and then rendering a show page with the status update information. Clearly, I have no idea how to actually capture the "name" key from the parsed JSON result as a param for the show method. I have tried creating a data_params method to contain it, but it did not work. I have tried implicitly calling the param on the find method in show (as above), to no avail. I have even tried calling a new api scrape in a params method and trying to parse the results into that, and nothing.
I'm guessing it is either some very simple mistake I'm not seeing (is my link_to actually pointing the right direction? are my api calls and JSON parsing done correctly [yes, I know I should create a separate method or helper for the api call, but that hasn't been working out for me so far--I keep breaking the app]? is this link actually supposed to call from the index method still?), or else something a bit more out of my depth.
Any ideas on where to go from here?

In this view:
<% #response.each do |data| %>
<ul>
<li>
<%= link_to data['name'].upcase, name_path(#name) %>
</li>
</ul>
<% end %>
You're using #name but you never actually assign a value to it in your index controller method. As a result - it gets passed to the name_path function with a value of nil. That throws an error because your route definition requires a name.
I think you want something like name_path(data['name']) or something along those lines.

Related

Form_for is giving me a No Method Error when trying to create a new object

So as it stands I have a form partial which starts off as:
<%= form_for(#merchandise) do |f| %>
It works perfectly for editing the data that I have already assigned in the rails console. When I try to use it for a "new" form that creates new merchandise (in this case the singular form of merchandise, I don't have nested resources, multiple models etc.), I get a no Method error that states
"undefined method 'merchandises_path' for #<#<Class:0x64eaef0>:0x95d2370>".
When I explicitly state the URL in the form_for method:
<%= form_for(#merchandise url:new_merchandise_path) do |f| %>
I get it to open and I finally have access to the form, however in this case I get a routing error that states
"No route matches [POST] "merchandise/new"".
I decided to write out that route in my routes file which previously just had:
root "merchandise#index" resources :merchandise
After I add the route it literally does nothing. I click submit and it takes me to the form but there is no new data in the database. I am at a complete loss and have been at this for hours googling and stack overflowing and I just don't know what to do anymore. All help is seriously appreciated. I'm adding a pastebin with all my code in the following url:
http://pastebin.com/HDJdTMDt
I have two options for you to fix it:
Option 1:
Please try to do this for best practice in Rails:
routes.rb
change your routes use plural
resources :merchandises
merchandises_controller.rb
Rename your file controller and class into MerchandisesController
class MerchandisesController < ApplicationController
def index
#merchandise = Merchandise.all
end
def new
#merchandise = Merchandise.new
end
def create
#merchandise = Merchandise.new(merchandise_params)
if #merchandise.save
redirect_to merchandises_path
else
render :new
end
end
def show
#merchandise = Merchandise.find(params[:id])
end
def edit
#merchandise = Merchandise.find(params[:id])
end
def update
#merchandise = Merchandise.find(params[:id])
if #merchandise.update(merchandise_params)
redirect_to #merchandise, notice: "The movie was updated"
else
render :edit
end
end
def merchandise_params
params.require(:merchandise).permit(:shipper, :cosignee, :country_arrival_date, :warehouse_arrival_date, :carrier, :tracking_number, :pieces, :palets, :width, :height, :length, :weight, :description, :cargo_location, :tally_number, :customs_ref_number, :released_date, :updated_by, :country_shipped_to, :country_shipped_from)
end
end
Option 2:
If you want to not change many code
/merchandise/_form.html.erb
in partial file
/merchandise/new.html.erb
<%= render 'form', url: merchandise_path, method: 'post' %>
/merchandise/edit.html.erb
<%= render 'form', url: category_path(#merchendise.id), method: 'put' %>

How to pass params to new view in Ruby on Rails app?

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.

How do I get and display JSON with HTTParty?

I'm new to Ruby on Rails and programming in general. So far I've successfully used my console to return JSON data from an API but I can't seem to make it work on my local server.
In the console I entered:
httparty "http://rubygems.org/api/v1/versions/httparty.json"
and it returned the JSON after I managed to install/configure everything.
So then in the console I wrote:
rails new Catalog
rails generate controller new index
I followed the tutorial to get <h1>Hello, Rails!</h1> to display on my page when I go to:
http://localhost:3000/
Now I am trying to get the JSON data returned and display on that same page where it says "Hello, Rails".
In index.html.erb I have:
<h1>Hello, Rails</h1>
<%= #result %>
In home_controller.rb I have:
class HomeController < ApplicationController
def get_catalog
include HTTParty
#result = HTTParty.get("http://rubygems.org/api/v1/versions/httparty.json")
end
end
In routes.rb I have:
Catalog::Application.routes.draw do
get "home/index"
root :to => 'home#index'
end
Nothing appears under "Hello, Rails" when I go to the page.
I'm still trying to wrap my head around how all of this stuff interacts with each other. Can anyone see what I'm doing wrong here perhaps?
--- Update
I'm trying to output just the product names into li elements. My files now are:
index.html.erb:
<ul>
<% #http_party_json.each do |event| %>
<% event.each do |e| %>
<li><%=h e['Products']['Name'] %></li>
<% end %>
<% end %>
</ul>
controller:
class HomeController < ApplicationController
def index
#response = HTTParty.get("myURL")
#http_party_json = JSON.parse(#response.body)
end
end
The error I am getting is:
undefined method `[]' for nil:NilClass
Extracted source (around line #5):
2: <ul>
3: <% #http_party_json.each do |event| %>
4: <% event.each do |e| %>
5: <li><%=h e['Products']['Name'] %></li>
6: <% end %>
7: <% end %>
8: </ul>
When I take off the ['Name'] I get JSON starting with:
[{"Name"=>"3x4 Vinyl Magnet", "Description"=>"Made of durable high-gloss vinyl. Measures 3x4 inches and has rounded corners. Waterproof and scratch resistant."
Why can't I target ['Name'] to get just the product names?
HTTParty parses XML/JSON responses for you. Simply use parsed_response to get it:
#response = HTTParty.get("URL").parsed_response
HTTParty.get returns an object of the type HTTParty::Response, which is documented in HTTParty (Check out the examples.)
There is a nice helper method on HTTParty::Response called `#parsed_response. This returns the JSON string parsed into a Hash or Array:
HTTParty.get("URL").parsed_response
Alternatively, in order to get the body of this message, you can call #result.body. This returns a string, which you can safely output to your page as you did. However, I'm guessing you want to do more with it than just output it to a page.
In order to parse this into a hash/Array that you can use/manipulate/return as true JSON you would do something like:
http_party_json = JSON.parse(#response.body)
So with this, you could do something like the following in your controller if you wanted to be able to return JSON:
#response = HTTParty.get("http://rubygems.org/api/v1/versions/httparty.json").parsed_response
respond_to do |format|
format.json { render :json => JSON.parse(#result) }
format.html { render "index.html.erb" }
end
Updated answer based on your updated information:
It appears as though e['Products'] returns an array (notice the square brackets on the outside.) So, if you are only expecting one you could do:
e['Products'][0]['Name']
If it might return multiple products, you might, instead, need to account for the possibility of many products and use an each block:
e['Products'].each do |product|
#do something with product['Name']
end
It just depends on your needs for the app.

Rails: link_to calls custom method in controller

I am looking to use link_to to call a method in my controller. However, for some odd reason the route looks for the show method.
In my view:
<% #beverages.each do |beverage| %>
..
<%= link_to 'Archive', beverages_archive_path(:id => beverage.id) %>
..
<% end %>
In my config/routes.rb
match 'beverages/archive' => 'beverages#archive'
In my beverages_controller.rb
def archive
beverage = Beverage.find(params[:id])
respond_to do |format|
# format.html # show.html.erb
format.json { render json: beverage }
end
# beverage.update_attribute('archive', true)
end
When I click on the archive link in the view, the URL does change to: http://localhost:3000/beverages/archive?id=11, however I get the following error.
The error I get:
ActiveRecord::RecordNotFound (Couldn't find Beverage with id=archive):
app/controllers/beverages_controller.rb:46:in `show'
Any idea on what I am doing wrong? Your help is much appreciated!
PS. I also looked at Rails 3 link_to delete destory method calls show method?
but nothing seemed to work.
Have you tried this in your routes?
match 'beverages/:id/archive' => 'beverages#archive', as: :beverages_archive
This will create the beverages_archive_path method for you. Also, as you are looking for a specific beverage, use :id inside the route so that it knows where to take the id parameter from.
Apart from that, you can always tell a link specifically which controller and action to link to by doing:
link_to "Label", :controller => :my_controller, :action => :index
Taken from here: Ruby on rails 3 link_to controller and action
Use the other notation (not match) instead.
resources :beverages do
collection do
get :archive
end
end
Try this one out and let me know if something went wrong.
There's not quite enough information here to know why beverages_archive_path works in your app -- one problem is that your routes file does not define a name for your beverages#archive route. What you want is something like:
match 'beverages/archive' => 'beverages#archive', :as => :beverages_archive
or better yet use resourceful routing conventions like so:
resources :beverages do
collection do
get :archive
end
end
What's happening is that you have a beverages#show route that matches /beverages/:id, and this is what /beverages/archive matches (with :id => 'archive').

ruby on rails implement search with auto complete

I've implemented a search box that searches the "Illnesses" table and the "symptoms" table in my DB.
Now I want to add auto-complete to the search box.
I've created a new controller called "auto_complete_controller" which returns the auto complete data.
I'm just not sure how to combine the search functionality and the auto complete functionality: I want the "index" action in my search controller to return the search results, and the "index" action in my auto_complete controller to return the auto_complete data.
Please guide me how to fix my html syntax and what to write in the js.coffee file.
I'm using rails 3.x with the jquery UI for auto-complete, I prefer a server side solution, and this is my current code:
main_page/index.html.erb:
<p>
<b>Syptoms / Illnesses</b>
<%= form_tag search_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %> <br/>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
</p>
auto_complete_controller.rb:
class AutoCompleteController < ApplicationController
def index
#results = Illness.order(:name).where("name like ?", "%#{params[:term]}%") + Symptom.order(:name).where("name like ?", "%#{params[:term]}%")
render json: #results.map(&:name)
end
end
search_controller.rb:
class SearchController < ApplicationController
def index
#results = Illness.search(params[:search]) + Symptom.search(params[:search])
respond_to do |format|
format.html # index.html.erb
format.json { render json: #results }
end
end
end
Thanks, Li
I have had the same problem and had to create this gem for it: https://github.com/rayasocialmedia/rails_autocomplete
Here's how to do dynamic typeahead in Twitter-Bootstrap; I'm sure it's something similar for jQuery:
https://gist.github.com/1848558
Essentially, by listening to to non-navigational keystrokes, it triggers an AJAX partial text search to your controller. This return data then populates the JS framework's typeahead/autocomplete data to be displayed. This means that you really only need the one SearchController.
Try rails3-jquery-autocomplete. I am using it and had the same requirements as you, and they work fine together. Let me know if you need further help.

Resources