[Rails Level 2] RENDERING EXTREMITIES -- Ex (Return in Json, resoure route)
RENDER
Complete the method below so that if the ammo is low it will render the fire_and_reload view, otherwise it should render the fire_weapon view.
1. In this case, render will take a single argument that maps to the name of the view. 2. If you don't call render, Rails will automatically render the view of the same name as the action 3. The correct answer should be: class WeaponsController < ApplicationController def fire_weapon @weapon = Weapon.find(params[:id]) @weapon.fire! if @weapon.low_ammo? render :fire_and_reload end end end
CUSTOM RESOURCE ROUTES
Create two custom member routes on the weapons resource, so you have a put method calledtoggle_condition and a put method called reload.
1. To add routes to the :weapons resource pass a block, like this: resources :weapons do # custom routes go here end 2. To add a custom route, call the HTTP method and then pass in the name, like this: resources :weapons do put :toggle_condition, on: :member end RailsForZombies::Application.routes.draw do resources :zombies do resources :weapons do put :toggle_condition, on: :member put :reload, on: :member end end end
RENDER JSON
Complete the create method below. When @weapon.save is successful it should render the @weapon object in JSON, have status :created, and set the location to the @weapon's show url. When @weapon.save fails it should return the @weapon.errors and have the status:unprocessable_entity.
1. To render a @weapon as json, you can do this: render json: @weapon 2. render takes the options :status and :location, like this: render json: @weapon, status: :created, location: @weapon class WeaponsController < ApplicationController def create @weapon = Weapon.new(params[:weapon]) if @weapon.save render json: @weapon, status: :created, location: @weapon else render json: @weapon.errors, status: :unprocessable_entity end end end
RENDER JSON W/OPTIONS
Complete the controller so that it returns in JSON only the amount of ammo which is left in the weapon. If the ammo has less than 30 bullets it should return the status code :ok, and if not it should return the status code :unprocessable_entity.
1. To limit the json that is output, you'd use to_json and pass in the :only option, like this: @weapon.to_json(only: :ammo) 2. render takes the option :status, like this: render json: @weapon.to_json(only: :ammo), status: :ok class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) render json: @weapon.to_json(only: :ammo), status: :ok else render json: @weapon.to_json(only: :ammo), status: :unprocessable_entity end end end
MORE TO JSON OPTIONS
Modify the show action so that the JSON it renders includes the zombie record the @weapon belongs to. Also make it exclude the :id, :created_at, and :updated_at fields.
1. To exclude some data in a to_json call, use :except, like this: @weapon.to_json(except: [:updated_at, :id, :created_at]) 2. To include an association in a to_json call, use the :include option, like this: @weapon.to_json(except: [:updated_at, :id, :created_at], include: :zombie) class WeaponsController < ApplicationController def show @weapon = Weapon.find(params[:id]) render json: @weapon.to_json(except: [:id, :created_at, :updated_at], include: :zombie) end end
AS JSON
Edit the as_json method so the Zombie class only returns the zombie's name and weapons (useinclude). Only return the weapon's name and ammo.
class Zombie < ActiveRecord::Base has_many :weapons def as_json(options=nil) super (options || {only: :name, include: {weapons: {only: [:name, :ammo]}}}) end end
LINK REMOTE
Modify the show.html.erb view below so that both the Toggle link and the Reload form use AJAX. All you need to do is add the option that makes them ajaxified.
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
1. Use the remote option to make a link use Ajax, like this: link_to "Toggle", toggle_condition_weapon_path(@weapon), remote: true <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_weapon_path(@weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <%= form_for @weapon, url: reload_weapon_path(@weapon), remote: true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload"%> </div> <% end %>
AJAX RESPONSE
Modify the toggle_condition action so that it responds to JavaScript, and complete thetoggle_condition.js.erb using jQuery to update the condition span with the @weapon's changed condition and make it highlight.
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> </ul>
Answer:
weapons_controller.rb:
class WeaponsController < ApplicationController def toggle_condition @weapon = Weapon.find(params[:id]) @weapon.toggle_condition respond_to do |format| format.html { redirect_to @weapon, notice: 'Changed condition' } format.js end end end
toggle_condition.ks.erb:
1. To get an action to respond to an Ajax request, you need to add format.js, like this: respond_to do |format| format.html { redirect_to @weapon, notice: 'Changed condition' } format.js end 2. You can add javascript code with erb tags in toggle_condition.js.erb, like this: $('#condition').text("<%= @weapon.condition %>").effect("highlight") //=require jQuery_ui $("#condition").text("<%= @weapon.condition %>").effect('highlight')
AJAX RESPONSE II
Now write the controller and JavaScript code needed to properly reload the weapon using the ajaxified form. In the reload.js.erb use jQuery to update the #ammo text to the current @weapon.ammo value and if the ammo value is over or equal to 30, fadeOut the #reload_form div.
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <div id="reload_form"> <%= form_for [@user, @weapon], url: reload_user_weapon_path(@user, @weapon), remote:true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload" %> </div> <% end %> </div> <%= link_to 'Edit', edit_weapon_path(@weapon) %> | <%= link_to 'Back', weapons_path %>
Answer:
#weapons_controller.erb class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) respond_to do |format| if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) format.json { render json: @weapon.to_json(only: :ammo), status: :ok } format.html { redirect_to @weapon, notice: 'Weapon ammo reloaded' } else format.json { render json: @weapon.to_json(only: :ammo), status: :unprocessable_entity } format.html { redirect_to @weapon, notice: 'Weapon not reloaded' } end format.js end end end
$("#ammo").text("<%= @weapon.ammo %>") <% if @weapon.ammo >= 30%> $("#reload_form").fadeOut(); <% end %>
COFFEESCRIPT
Instead of returning jQuery which gets executed on the client-side, lets write the ajax request in CoffeeScript communicating with JSON. It should do the same thing as the last challenge, updating & highlighting the ammo, and fading out the form (hint: fade out the wrapper element) if ammo is equal or above 30.
Tip for your ajax form: data: {ammo_to_reload: ammo}.
class WeaponsController < ApplicationController def reload @weapon = Weapon.find(params[:id]) respond_to do |format| if @weapon.ammo < 30 @weapon.reload(params[:ammo_to_reload]) format.json { render :json => @weapon.to_json(:only => :ammo), status: :ok } format.html { redirect_to @weapon, notice: 'Weapon ammo reloaded' } else format.json { render :json => @weapon.to_json(:only => :ammo), status: :unprocessable_entity } format.html { redirect_to @weapon, notice: 'Weapon not reloaded' } end format.js end end end
<p id="notice"><%= notice %></p> <ul> <li> <em>Name:</em> <%= @weapon.name %> </li> <li> <em>Condition:</em> <span id="condition"><%= @weapon.condition %></span> <%= link_to "Toggle", toggle_condition_user_weapon_path(@user, @weapon), remote: true %> </li> <li> <em>Ammo:</em> <span id="ammo"><%= @weapon.ammo %></span> </li> </ul> <div id="reload_form"> <%= form_for [@user, @weapon], url: reload_user_weapon_path(@user, @weapon), remote:true do |f| %> <div class="field"> Number of bullets to reload: <%= number_field_tag :ammo_to_reload, 30 %> <br /> <%= f.submit "Reload" %> </div> <% end %> </div> <%= link_to 'Edit', edit_weapon_path(@weapon) %> | <%= link_to 'Back', weapons_path %>
Answer:
$(document).ready -> $('div#reload_form form').submit (event) -> event.preventDefault() url = $(this).attr('action') ammo = $('#ammo_to_reload').val() $.ajax type: 'put', data: {ammo_to_reload: ammo}, url: url, dataType: 'json', success: (json)-> $("#ammo").text(json.ammo).effect('highlight') if json.ammo >= 30 $("#reload_form").fadeOut()
相关文章
- python的json模块
- 在php中如何使用json_decode解析gbk编码的json字符串
- Jmeter入门15 JSON Assertion 适用于json格式的响应断言
- vue-json-excel导出数字字符串转为科学计数法问题和文件格式问题
- JQuery处理json与ajax返回JSON实例
- php xml与json间的相互转换
- SAP UI5 manifest.json 和 i18n 多语言文本的解析逻辑
- 如何用CL_CLB_PARSE_JSON解析json字符串到动态生成的ABAP内表结构里
- C# 如何识别一个字符串是否Json格式
- 关于 Angular 项目类型为 library 的工程使用 tsconfig.json 的问题
- Android 手动解析JSON数据
- 灵活运用JSON
- Qt中JSON简介
- 微信小程序——标签wxml、样式wxss、js、json
- filebeat收集json格式的nginx程序日志(二)
- filebeat收集json格式的tomcat日志(七)