我使用rails(5.0.1)和active_model_serializers(0.10.2)。我想以某种方式有条件地序列化import React, {Component} from 'react';
import {reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import map from 'lodash/map';
import timezones from '../../data/timezones';
import styles from '../formElements/formElements.scss';
import {registerUser} from '../../actions/actionRegister';
import {formUpdate} from '../../actions/actionForm';
import FieldGroup from '../formElements/FieldGroup';
import { Form, FormControl, Col, Checkbox, Button, FormGroup } from 'react-bootstrap';
// {... props} passing large number of props wrap in object with spread notation
class SignupForm extends Component { //if component have state it needs to be class
constructor(props) {
super(props);
this.state = {
errors: { //this errors are irrelevant for now
name:'',
email: '',
password: '',
passwordConfirmation:'',
timezone:''
},
};
}
onChange = (event, index, value) => {
this.props.onChange(event.target.name, event.target.value);
};
onSave = (event) => {
event.preventDefault();
this.props.onSave(this.props.values);
}
render() {
let isLoading = this.props.isLoading;
return (
// this.props.handleSubmit is created by reduxForm()
// if the form is valid, it will call this.props.onSubmit
<Form onSubmit={this.onSave} horizontal>
<FieldGroup
id="formControlsName"
type="text"
label="Name"
name="name"
placeholder="Enter Name"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.name}
/>
<FieldGroup
id="formControlsEmail"
type="text"
label="Email"
name="email"
placeholder="Enter Email"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.email}
/>
<FieldGroup
id="formControlsPassword"
type="password"
label="Password"
name="password"
placeholder="Enter Password"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.password}
/>
<FieldGroup
id="formControlsPasswordConfirmation"
type="password"
label="Password Confirmation"
name="passwordConfirmation"
placeholder="Enter Password"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.passwordConfirmation}
/>
<FieldGroup
id="formControlsTimezone"
label="Time Zone"
name="timezone"
placeholder="Select Time Zone"
componentClass="select"
defaultValue="Select Your Timezone"
value={this.props.values[name]}
onChange={this.onChange}
help={this.state.errors.timezone}
>
<option value="Select Your Timezone">Select Your Timezone</option>
{
map(timezones, (key, value) =>
<option key={key} value={key}>{value}</option>)
}
</FieldGroup>
<FormGroup>
<Col smOffset={4} sm={8}>
<Checkbox>Remember me</Checkbox>
</Col>
</FormGroup>
<FormGroup>
<Col smOffset={4} sm={8}>
<Button type="submit" disabled={isLoading}
onClick={!isLoading ? isLoading : null}
>
{ isLoading ? 'Creating...' : 'Create New Account'}
</Button>
</Col>
</FormGroup>
{this.props.errorMessage && this.props.errorMessage.register &&
<div className="error-container">{this.props.errorMessage.register}</div>}
</Form>
//this.setState({ disabled: true });
//this.props.errorMessage.register == this.props = {errorMessage :{ register: ''}}
);
}
}
function mapStateToProps(state) {
return {
errorMessage: state.signup.error,
isLoading: state.signup.isLoading,
values: state.form.values
};
}
function mapDispatchToProps(dispatch) {
return {
onSave: (values) => dispatch(registerUser(values)),
onChange: (name, value) => dispatch(formUpdate(name, value))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(SignupForm)
关联:
has_many
我使用jsonapi并查询class Question < ApplicationRecord
has_many :responses, :inverse_of => :question
end
class Response < ApplicationRecord
belongs_to :question, :inverse_of => :responses
end
class QuestionSerializer < ActiveModel::Serializer
attributes :id, :title, :created_at, :updated_at
has_many :responses
end
class ResponseSerializer < ActiveModel::Serializer
attributes :id, :title
end
我得到了这个回复:
响应-1 :
http://localhost:3000/api/questions/1
如果我从{
"data": {
"id": "1",
"type": "questions",
"attributes": {
"title": "First",
"created-at": "2017-02-14T09:49:20.148Z",
"updated-at": "2017-02-14T13:55:37.365Z"
},
"relationships": {
"responses": {
"data": [
{
"id": "1",
"type": "responses"
}
]
}
}
}
}
删除has_many :responses
,我就明白了:
响应-2 :
QuestionSerializer
我如何有条件地在运行时获得 Response-1 或 Response-2 ?我尝试了所有建议 - 不适用于AMS 0.10.2。目前,条件只有这样:
{
"data": {
"id": "1",
"type": "questions",
"attributes": {
"title": "First",
"created-at": "2017-02-14T09:49:20.148Z",
"updated-at": "2017-02-14T13:55:37.365Z"
}
}
}
OR:
class QuestionSerializer < ActiveModel::Serializer
attributes :id, :title, :created_at, :updated_at
has_many :responses if true
end
在这2个案例中,我真的得到 Response-1 或 Response-2 。但这是硬编码的,我想将一个参数传递给序列化器或做一些类似的事情。
我该怎么办?
答案 0 :(得分:2)
我认为你已经回答了自己的问题。如果您查看AMS documentation for associations,它会说支持条件。
从我可以告诉你的只是一个错字
class QuestionSerializer < ActiveModel::Serializer
has_many :responses, if: false
end
attributes
方法也支持if
选项,如here所述。
你的active_model_serializers
版本是什么?
修改强>:
我的答案也有错误。我正在使用active_model_serializers (0.10.3)
而我能够
class QuestionSerializer < ActiveModel::Serializer
has_many :responses, if: -> { false }
end
if
选项适用于方法,过程或字符串。我认为你可以在运行时通过提供一个方法作为条件来决定。
class QuestionSerializer < ActiveModel::Serializer
attr_writer :should_render_association
has_many :responses, if: -> { should_render_association }
end
# Usage:
serializer = QuestionSerializer.new(question)
serializer.should_render_association = false
serializer.to_json
# => no "responses" key
答案 1 :(得分:2)
感谢@gkats,我找到了答案(AMS 0.10.2):
class QuestionSerializer < ActiveModel::Serializer
attributes :id, :title, :created_at, :updated_at
has_many :responses, if: -> { should_render_association }
def should_render_association
@instance_options[:show_children]
end
end
class Api::ResponsesController < Api::ApplicationController
def show
render json: @response, show_children: param[:include_children]
end
end
问题在于语法:序列化程序中的if:
应该应用于块而不是函数。
答案 2 :(得分:0)
我为同一问题苦苦挣扎。这是我想出的有效解决方案。
以except: [:key_one, :key_two]
作为参数进行初始化。
class QuestionsController
def index
@questions = Question.all
render(json: ActiveModel::ArraySerializer.new(@questions,
each_serializer: QuestionSerializer,
root: 'questions',
except: [:responses])
)
end
def show
# you can also pass the :except arguments here
# render(json: QuestionSerializer.new(@question, except: [:responses]).to_json)
render(json: QuestionSerializer.new(@question).to_json)
end
end
https://www.rubydoc.info/gems/active_model_serializers/0.9.1/ActiveModel%2FSerializer:initialize
答案 3 :(得分:0)
这里是如何从父串行器传递参数,并在子串行器中基于这些参数显示或隐藏属性。
父级序列化器:
class LocationSharesSerializer < ActiveModel::Serializer
attributes :id, :locations, :show_title, :show_address
def locations
ActiveModelSerializers::SerializableResource.new(object.locations, {
each_serializer: PublicLocationSerializer,
params: {
show_title: object.show_title
},
})
end
end
子序列化器
class PublicLocationSerializer < ActiveModel::Serializer
attributes :id, :latitude, :longitude, :title, :directions, :description, :address, :tags, :created_at, :updated_at, :photos
def title
object.title if @instance_options[:params][:show_title]
end
end