更好的尝试方法

时间:2019-03-01 16:55:23

标签: ruby-on-rails ruby activesupport

我想要一段干净的代码,我觉得这很笨拙。

有更好的方法吗?

User.try(:profile).try(:settings).try(:card).try(:options)

如果取消使用try方法,则会出现nil方法错误。

还有另一段代码可以执行以下操作吗?

User.try(:profile,:settings, :card, :options)

4 个答案:

答案 0 :(得分:5)

从ruby 2.3.0开始,您可以使用&.方法代替try

User&.profile&.settings&.card&.options

但是您应该避免这样的事情。

当您向可能返回nil的对象发送消息时,或者当对象不响应该消息时,则应自行解决此问题。与try检查一样,使用nil只会加剧问题。 编写行为一致的一致接口。

答案 1 :(得分:3)

如果您使用的Ruby版本大于2.3,则可以使用安全运算符。例如,

demo.py

不是很整洁吗?

答案 2 :(得分:3)

很有趣

自己滚动:

# concerns/deep_try.rb

module DeepTry
  def deep_try(*methods)
    methods.reduce(self) { |receiver, method| receiver.try(method) }
  end
end

# user.rb (or anywhere else you want it)
extend DeepTry

这样可以让您安全地拨打以下电话:

User.deep_try(:profile, :settings, :card, :options)

您还可以在实例级别使用:

@user.extend(DeepTry).deep_try(:profile, :settings, :card, :options)

答案 3 :(得分:0)

我知道这是在左手边,但你知道,思维的多样性。

我创建了一个(非常微小的)无能的宝石,该宝石允许在担心错误的情况下执行代码。使用此gem的代码如下所示:

    import React, { Component } from "react";
import { StyleSheet, Text, View, TouchableOpacity } from "react-native";
import Icon from "@expo/vector-icons/Ionicons";
import {
  createAppContainer,
  createDrawerNavigator,
  createBottomTabNavigator,
  createStackNavigator
} from "react-navigation";
import { Constants } from "expo";

const DrawerMenuItems = [
  {
    title: "Login",
    icon: "ios-home",
    navigateTo: "Login"
  },
  {
    title: "Feedback",
    icon: "ios-home",
    navigateTo: "Feedback"
  },
  {
    title: "Help",
    icon: "ios-help",
    navigateTo: "Help"
  }
];

export default class App extends React.Component {
  render() {
    return <AppContainer />;
  }
}

class HomeScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>HomeScreen</Text>
      </View>
    );
  }
}

class ContactScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>ContactScreen</Text>
      </View>
    );
  }
}

class AboutScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>AboutScreen</Text>
      </View>
    );
  }
}

class LoginScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>LoginScreen</Text>
      </View>
    );
  }
}

class FeedbackScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>FeedbackScreen</Text>
      </View>
    );
  }
}

class HelpScreen extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text>HelpScreen</Text>
      </View>
    );
  }
}

class HamburgerMenu extends Component {
  constructor(props) {
    super(props);
  }

  renderMenu(menuItems) {
    {
      return menuItems.map((item, index) => {
        return (
          <View style={{ width: "100%" }} key={index}>
            <View style={styles.sideMenuItem}>
              <TouchableOpacity
                style={styles.sideMenuIcon}
                onPress={() => {
                  this.props.navigation.navigate(item.navigateTo);
                }}
              >
                <Icon name={item.icon} size={30} />
              </TouchableOpacity>

              <Text
                style={styles.menuText}
                onPress={() => {
                  this.props.navigation.navigate(item.navigateTo);
                }}
              >
                {item.title}
              </Text>
            </View>
          </View>
        );
      });
    }
  }

  render() {
    return (
      <View style={styles.sideMenuContainer}>
        {this.renderMenu(DrawerMenuItems)}
      </View>
    );
  }
}

const DrawerButton = ({ navigation }) => (
  <TouchableOpacity onPress={() => navigation.openDrawer()}>
    <Icon style={styles.menuIcon} name="md-menu" size={30} />
  </TouchableOpacity>
);

const BottomTabsNavigator = createBottomTabNavigator(
  {
    Home: HomeScreen,
    Contact: ContactScreen,
    About: AboutScreen
  },
  {
    tabBarOptions: {
      activeTintColor: "#000",
      inactiveTintColor: "gray",
      style: {
        backgroundColor: "#fff"
      },
      indicatorStyle: {
        backgroundColor: "#000"
      }
    }
  }
);

const AppDrawNavigator = createDrawerNavigator(
  {
    Main: { screen: BottomTabsNavigator }
  },
  {
    contentComponent: HamburgerMenu,
    drawerPosition: "right"
  }
);

const AppStackNavigator = createStackNavigator(
  {
    MainDrawNavigator: {
      screen: AppDrawNavigator
    }
  },
  {
    defaultNavigationOptions: ({ navigation }) => {
      return {
        header: (
          <View style={styles.header}>
            <DrawerButton navigation={navigation} />
          </View>
        ),
        headerStyle: {
          height: 60
        }
      };
    }
  }
);

const AppContainer = createAppContainer(AppStackNavigator);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center"
  },
  sideMenuContainer: {
    width: "100%",
    height: "100%",
    backgroundColor: "#fff",
    alignItems: "center",
    paddingTop: 20
  },
  sideMenuProfileIcon: {
    resizeMode: "center",
    width: 150,
    height: 150,
    borderRadius: 150 / 2
  },
  sideMenuIcon: {
    resizeMode: "center",
    width: 28,
    height: 28,
    marginRight: 10,
    marginLeft: 20
  },
  menuIcon: {
    left: 10
  },
  menuText: {
    fontSize: 15,
    color: "#222222"
  },
  header: {
    paddingTop: Constants.statusBarHeight,
    backgroundColor: "#e1e8ee",
    flexDirection: "row"
  }
});

添加了捕获所有标准错误的“好处”,而不仅仅是nil方法错误。错误时返回nil值。如果在您的应用程序中更有意义,则可以将其替换为其他值。

完全省略该参数将以字符串形式返回错误消息。