草庐IT

flutter - 如何使用 Form 和 GlobalKey 验证 alertDialog 上的文本输入?

coder 2023-07-22 原文

我在 alertDialog 上有一个 textfield,它接受 Email 并想要验证它。点击 忘记密码 按钮后,alertDialog 在当前登录屏幕前打开。 我已经实现了登录验证,并试图使用类似的逻辑来实现上述目标。对于登录验证,我使用了完美运行的 GlobalKey(_formKey) 和 Form 小部件。我正在使用另一个名为 _resetKeyGlobalKey 来获取验证的 currentState,然后保存它的状态。虽然这种方法有效,但我看到验证消息也显示在 EmailPassword 字段中。即,如果我点击打开对话框的“忘记密码”,然后点击发送电子邮件,它会正确显示验证消息,但同时,登录屏幕的验证消息也会在之后触发点击警报对话框中的取消按钮。像这样:

对于 alertDialog 验证,下面是我的代码:

// Creates an alertDialog for the user to enter their email
  Future<String> _resetDialogBox() {
    final resetEmailController = TextEditingController();

    return showDialog<String>(
      context: context,
      barrierDismissible: false, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
          title: new Text('Reset Password'),
          content: new SingleChildScrollView(
              child: new Form(
                key: _resetKey,
                autovalidate: _validate,
                child: ListBody(
                  children: <Widget>[
                    new Text(
                      'Enter the Email Address associated with your account.',
                      style: TextStyle(fontSize: 14.0),),
                    Padding(
                      padding: EdgeInsets.all(10.0),
                    ),
                    Row(
                      children: <Widget>[
                        new Padding(
                          padding: EdgeInsets.only(top: 8.0),
                          child: Icon(
                            Icons.email, size: 20.0,
                          ),
                        ),
                        new Expanded(
                          child: TextFormField(
                            validator: validateEmail,
                            onSaved: (String val) {
                              resetEmail = val;
                            },

new FlatButton(
              child: new Text(
                'SEND EMAIL', style: TextStyle(color: Colors.black),),
              onPressed: () {
                setState(() {
                  _sendResetEmail();
                });

void _sendResetEmail() {
    final resetEmailController = TextEditingController();
    resetEmail = resetEmailController.text;

    if (_resetKey.currentState.validate()) {
      _resetKey.currentState.save();

      try {
        Fluttertoast.showToast(
            msg: "Sending password-reset email to: $resetEmail",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 4);

        _auth.sendPasswordResetEmail(email: resetEmail);
      } catch (exception) {
        print(exception);

        Fluttertoast.showToast(
            msg: "${exception.toString()}",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 4);
      }
    }
    else {
      setState(() {
        _validate = true;
      });
    }
  }

使用 _formKey 要点的登录验证如下:

// Creates the email and password text fields
  Widget _textFields() {
    return Form(
        key: _formKey,
        autovalidate: _validate,
        child: Column(
          children: <Widget>[
            Container(
              decoration: new BoxDecoration(
                border: new Border(
                  bottom: new BorderSide(width: 0.5, color: Colors.grey),
                ),
              ),
              margin: const EdgeInsets.symmetric(
                  vertical: 25.0, horizontal: 65.0),

              // Email text field
              child: Row(
                children: <Widget>[
                  new Padding(
                    padding: EdgeInsets.symmetric(
                        vertical: 10.0, horizontal: 15.0),
                    child: Icon(
                      Icons.email,
                      color: Colors.white,
                    ),
                  ),
                  new Expanded(
                    child: TextFormField(
                      validator: validateEmail,
                      onSaved: (String val) {
                        email = val;
                      },

我认为它必须用 2 个键做一些事情,因为 alertDialog 显示在当前事件的前面。我如何使用 _formKey 或是否有任何其他方法来实现?

************ 需要完整代码 ************

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: LoginScreen(),
      ),
    );
  }
}


class LoginScreen extends StatefulWidget {
  @override
  LoginScreenState createState() => new LoginScreenState();
}

class LoginScreenState extends State<LoginScreen> {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  final _formKey = GlobalKey<FormState>();
  final _resetKey = GlobalKey<FormState>();
  bool _validate = false;
  String email;
  String password;
  String resetEmail;

  // The controller for the email field
  final _emailController = TextEditingController();

  // The controller for the password field
  final _passwordController = TextEditingController();

  // Creates the 'forgot password' and 'create account' buttons
  Widget _accountButtons() {
    return Container(
      child: Expanded(
          child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      Container(
                        child: new FlatButton(
                          padding: const EdgeInsets.only(
                              top: 50.0, right: 150.0),
                          onPressed: () => sendPasswordResetEmail(),
                          child: Text("Forgot Password",
                              style: TextStyle(color: Colors.white)),
                        ),
                      )
                    ]),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    Container(
                      child: new FlatButton(
                        padding: const EdgeInsets.only(top: 50.0),
                        onPressed: () =>
                            Navigator.push(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => CreateAccountPage())),
                        child: Text(
                          "Register",
                          style: TextStyle(color: Colors.white),
                        ),
                      ),
                    )
                  ],
                )
              ])),
    );
  }

  // Creates the email and password text fields
  Widget _textFields() {
    return Form(
        key: _formKey,
        autovalidate: _validate,
        child: Column(
          children: <Widget>[
            Container(
              decoration: new BoxDecoration(
                border: new Border(
                  bottom: new BorderSide(width: 0.5, color: Colors.grey),
                ),
              ),
              margin: const EdgeInsets.symmetric(
                  vertical: 25.0, horizontal: 65.0),

              // Email text field
              child: Row(
                children: <Widget>[
                  new Padding(
                    padding: EdgeInsets.symmetric(
                        vertical: 10.0, horizontal: 15.0),
                    child: Icon(
                      Icons.email,
                      color: Colors.white,
                    ),
                  ),
                  new Expanded(
                    child: TextFormField(
                      validator: validateEmail,
                      onSaved: (String val) {
                        email = val;
                      },
                      keyboardType: TextInputType.emailAddress,
                      autofocus: true,
                      // cursorColor: Colors.green,
                      controller: _emailController,
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: 'Email',

                        //  contentPadding: EdgeInsets.fromLTRB(45.0, 10.0, 20.0, 1.0),
                        contentPadding: EdgeInsets.only(left: 55.0, top: 15.0),
                        hintStyle: TextStyle(color: Colors.white),
                      ),
                      style: TextStyle(color: Colors.white),
                    ),
                  )
                ],
              ),
            ),

            // Password text field
            Container(
              decoration: new BoxDecoration(
                border: new Border(
                  bottom: new BorderSide(
                    width: 0.5,
                    color: Colors.grey,
                  ),
                ),
              ),
              margin: const EdgeInsets.symmetric(
                  vertical: 10.0, horizontal: 65.0),
              child: Row(
                children: <Widget>[
                  new Padding(
                    padding: EdgeInsets.symmetric(
                        vertical: 10.0, horizontal: 15.0),
                    child: Icon(
                      Icons.lock,
                      color: Colors.white,
                    ),
                  ),
                  new Expanded(
                    child: TextFormField(
                        validator: _validatePassword,
                        onSaved: (String val) {
                          password = val;
                        },
                        //  cursorColor: Colors.green,
                        controller: _passwordController,
                        decoration: InputDecoration(
                          border: InputBorder.none,
                          hintText: 'Password',
                          contentPadding: EdgeInsets.only(
                              left: 50.0, top: 15.0),
                          hintStyle: TextStyle(color: Colors.white),
                        ),
                        style: TextStyle(color: Colors.white),

                        // Make the characters in this field hidden
                        obscureText: true),
                  )
                ],
              ),
            )
          ],
        )
    );
  }

  // Creates the button to sign in
  Widget _signInButton() {
    return new Container(
        width: 200.0,
        margin: const EdgeInsets.only(top: 20.0),
        padding: const EdgeInsets.only(left: 20.0, right: 20.0),
        child: new Row(
          children: <Widget>[
            new Expanded(
              child: RaisedButton(
                  shape: new RoundedRectangleBorder(
                      borderRadius: new BorderRadius.circular(30.0)),
                  splashColor: Colors.white,
                  color: Colors.green,
                  child: new Row(
                    children: <Widget>[
                      new Padding(
                        padding: const EdgeInsets.only(left: 35.0),
                        child: Text(
                          "Sign in",
                          style: TextStyle(color: Colors.white, fontSize: 18.0),
                          textAlign: TextAlign.center,
                        ),
                      ),
                    ],
                  ),
                  onPressed: () {
                    setState(() {
                      _signIn();
                    });
                  }),
            ),
          ],
        ));
  }

  // Signs in the user
  void _signIn() async {
    // Grab the text from the text fields
    final email = _emailController.text;
    final password = _passwordController.text;

    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      try {
        Fluttertoast.showToast(
            msg: "Signing in...",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 2);

        firebaseUser = await _auth.signInWithEmailAndPassword(
            email: email, password: password);

        // If user successfully signs in, go to the pro categories page
        Navigator.pushReplacement(context,
            MaterialPageRoute(
                builder: (context) => ProCategories(firebaseUser)));
      } catch (exception) {
        print(exception.toString());

        Fluttertoast.showToast(
            msg: "${exception.toString()}",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 3);
      }
    }
    else {
      setState(() {
        _validate = true;
      });
    }
  }

  // Creates an alertDialog for the user to enter their email
  Future<String> _resetDialogBox() {
    final resetEmailController = TextEditingController();

    return showDialog<String>(
      context: context,
      barrierDismissible: false, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
          title: new Text('Reset Password'),
          content: new SingleChildScrollView(
              child: new Form(
                  key: _resetKey,
                  autovalidate: _validate,
                child: ListBody(
                  children: <Widget>[
                    new Text(
                      'Enter the Email Address associated with your account.',
                      style: TextStyle(fontSize: 14.0),),
                    Padding(
                      padding: EdgeInsets.all(10.0),
                    ),
                    Row(
                      children: <Widget>[
                        new Padding(
                          padding: EdgeInsets.only(top: 8.0),
                          child: Icon(
                            Icons.email, size: 20.0,
                          ),
                        ),
                        new Expanded(
                          child: TextFormField(
                               validator: validateEmail,
                               onSaved: (String val) {
                                 resetEmail = val;
                               },
                            keyboardType: TextInputType.emailAddress,
                            autofocus: true,
                            decoration: new InputDecoration(
                                border: InputBorder.none,
                                hintText: 'Email',
                                contentPadding: EdgeInsets.only(
                                    left: 70.0, top: 15.0),
                                hintStyle: TextStyle(
                                    color: Colors.black, fontSize: 14.0)
                            ),
                            style: TextStyle(color: Colors.black),
                          ),
                        )
                      ],
                    ),
                    new Column(
                        children: <Widget>[
                          Container(
                            decoration: new BoxDecoration(
                                border: new Border(
                                    bottom: new BorderSide(
                                        width: 0.5, color: Colors.black)
                                )
                            ),
                          )
                        ]
                    ),
                  ],
                ),
              )
          ),

          actions: <Widget>[
            new FlatButton(
              child: new Text('CANCEL', style: TextStyle(color: Colors.black),),
              onPressed: () {
                Navigator.of(context).pop("");
              },
            ),
            new FlatButton(
              child: new Text(
                'SEND EMAIL', style: TextStyle(color: Colors.black),),
              onPressed: () {
                setState(() {
                    _sendResetEmail();
                });
                Navigator.of(context).pop(resetEmail);
              },
            ),
          ],
        );
      },
    );
  }

  // Sends a password-reset link to the given email address
  void sendPasswordResetEmail() async {
    String resetEmail = await _resetDialogBox();

    // When this is true, the user pressed 'cancel', so do nothing
    if (resetEmail == "") {
      return;
    }

    try {
      Fluttertoast.showToast(
          msg: "Sending password-reset email to: $resetEmail",
          toastLength: Toast.LENGTH_LONG,
          bgcolor: "#e74c3c",
          textcolor: '#ffffff',
          timeInSecForIos: 4);

      _auth.sendPasswordResetEmail(email: resetEmail);
    } catch (exception) {
      print(exception);

      Fluttertoast.showToast(
          msg: "${exception.toString()}",
          toastLength: Toast.LENGTH_LONG,
          bgcolor: "#e74c3c",
          textcolor: '#ffffff',
          timeInSecForIos: 4);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // prevent pixel overflow when typing
      resizeToAvoidBottomPadding: false,
      body: Container(
        decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage(
                  "",
                ),
                fit: BoxFit.cover)),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            // QuickCarl logo at the top
            Image(
              alignment: Alignment.bottomCenter,
              image: AssetImage(""),
              width: 180.0,
              height: 250.0,
            ),
            new Text('',
                style: TextStyle(
                    fontStyle: FontStyle.italic,
                    fontSize: 12.0,
                    color: Colors.white)
            ),
            _textFields(),
            _signInButton(),
            _accountButtons()
          ],
        ),
      ),
    );
  }

  String validateEmail(String value) {
    String pattern = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
    RegExp regExp = new RegExp(pattern);
    if (value.length == 0) {
      return "Email is required";
    } else if (!regExp.hasMatch(value)) {
      return "Invalid Email";
    } else {
      return null;
    }
  }

  String _validatePassword(String value) {
    if (value.length == 0) {
      return 'Password is required';
    }

    if (value.length < 4) {
      return 'Incorrect password';
    }
  }

  void _sendResetEmail() {
    final resetEmailController = TextEditingController();
    resetEmail = resetEmailController.text;

    if (_resetKey.currentState.validate()) {
      _resetKey.currentState.save();

      try {
        Fluttertoast.showToast(
            msg: "Sending password-reset email to: $resetEmail",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 4);

        _auth.sendPasswordResetEmail(email: resetEmail);
      } catch (exception) {
        print(exception);

        Fluttertoast.showToast(
            msg: "${exception.toString()}",
            toastLength: Toast.LENGTH_LONG,
            bgcolor: "#e74c3c",
            textcolor: '#ffffff',
            timeInSecForIos: 4);
      }
    }
    else {
      setState(() {
        _validate = true;
      });
    }
  }
}

最佳答案

我知道这篇文章来不及了,但我想分享我的代码,以便同汤中的任何人都能从中获得帮助。该表单还使用正则表达式过滤器进行实时验证。

以下片段改编自 chemamolins 提供的解决方案从这个blog .

  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _phoneController = TextEditingController();
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final GlobalKey<FormFieldState> _nameFormKey = GlobalKey<FormFieldState>();
  final GlobalKey<FormFieldState> _phoneFormKey = GlobalKey<FormFieldState>();

  bool _isFormValid() {
    return ((_nameFormKey.currentState.isValid &&
        _phoneFormKey.currentState.isValid));
  }

  void _submit() {
    print('Name: ' +
        _nameController.text +
        ', problem: ' +
        _phoneController.text);
  }

  Future<void> _registerDialogBox(BuildContext context) async {
return await showDialog<String>(
    context: context,
    barrierDismissible: false,

    builder: (context) {

      bool _isSubmitButtonEnabled = false;
      return StatefulBuilder(builder: (context, setState) {
        return AlertDialog(
          scrollable: true,
          title: Text('Register'),
          content: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Form(
              key: _formKey,
              child: Column(
                children: <Widget>[
                  new TextFormField(
                    key: _nameFormKey,
                      controller: _nameController,
                      maxLength: 30,
                      maxLengthEnforced: true,
                      keyboardType: TextInputType.name,
                      inputFormatters: [new FilteringTextInputFormatter.allow(RegExp("[a-zA-Z]")), ],
                      decoration: InputDecoration(
                        labelText: 'Name',
                        icon: Icon(Icons.account_box),
                      ),
                      onChanged: (value) {
                        setState(() {
                          _isSubmitButtonEnabled = _isFormValid();
                          _nameFormKey.currentState.validate();
                        });
                      },
                      validator: (value) {
                        if (value.length < 3 )
                          return 'Min 3 and Max 30 characters';
                        else
                          return null;
                      }),
                  new TextFormField(
                      key: _phoneFormKey,
                      maxLength: 13,
                      maxLengthEnforced: true,
                      controller: _phoneController,
                      keyboardType: TextInputType.phone,
                      inputFormatters: [new FilteringTextInputFormatter.allow(RegExp("[0-9+]"))],
                      decoration: InputDecoration(
                        labelText: 'Phone',
                        icon: Icon(Icons.phone),
                      ),
                      onChanged: (value) {
                        setState(() {
                          _isSubmitButtonEnabled = _isFormValid();
                          _phoneFormKey.currentState.validate();
                        });
                      },
                      validator: (value) {
                        if (value.length > 1 && value.length < 10 )
                          return 'Minimum 10 digits';
                        else
                          return null;
                      }),
                ],
              ),
            ),
          ),
          actions: [
            RaisedButton(
                child: Text("Submit"),
                onPressed: _isSubmitButtonEnabled ? () => _submit() : null)
          ],
        );
      });
    });
  }

现在在 Widget build 中,可以这样调用 Future 函数:

Padding(
  padding: EdgeInsets.only(top: 5.0, bottom: 20.0),
  child: RaisedButton(onPressed: ()async {
    await _registerDialogBox(context);
  }),
),

关于flutter - 如何使用 Form 和 GlobalKey 验证 alertDialog 上的文本输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53061369/

有关flutter - 如何使用 Form 和 GlobalKey 验证 alertDialog 上的文本输入?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  4. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  5. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  6. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  9. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

随机推荐