草庐IT

android - 在操作栏中单击 "up"时,主/详细流程中的 Intent 为空(空指针异常)

coder 2023-12-13 原文

这可能有点冗长,所以我提前道歉。

我正在使用主/详细信息流来显示项目列表,单击它会打开详细信息 View 。这些项目是从网络服务加载的。 它在带有 fragment 的平板电脑上运行良好,但在手机上却一直崩溃。它可以正确显示项目详细信息 (CheatViewPageIndicator.java),但是当我使用操作栏左上角的“向上”按钮返回父 Activity (CheatListActivity.java) 时,应用程序不断崩溃并出现空指针异常。我想我在错误的位置从网络服务加载数据,这就是它崩溃的原因。我将在这里编写我的代码,希望有人可以给我建议,我必须如何以正确的方式执行此操作。

(我对类(class)进行了一些调整以缩短帖子的长度。)

“主” Activity :

public class CheatListActivity extends FragmentActivity implements CheatListFragment.Callbacks, ReportCheatDialogListener, RateCheatDialogListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cheat_list);

        settings = getSharedPreferences(Konstanten.PREFERENCES_FILE, 0);
        editor = settings.edit();

        cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 

        cheatProgressDialog = ProgressDialog.show(this, getString(R.string.please_wait) + "...", getString(R.string.retrieving_data) + "...", true);

        handleIntent(getIntent());

        if (findViewById(R.id.cheat_detail_container) != null) {
            // The detail container view will be present only in the
            // large-screen layouts (res/values-large and
            // res/values-sw600dp). If this view is present, then the
            // activity should be in two-pane mode.
            mTwoPane = true;

            // In two-pane mode, list items should be given the
            // 'activated' state when touched.
            ((CheatListFragment) getSupportFragmentManager().findFragmentById(R.id.cheat_list)).setActivateOnItemClick(true);
        }
        cheatProgressDialog.dismiss();
        // TODO: If exposing deep links into your app, handle intents here.

    }

    private void handleIntent(final Intent intent) {

        new Thread(new Runnable() {

            @Override
            public void run() {
                gameObj = new Gson().fromJson(intent.getStringExtra("gameObj"), Game.class);

                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        getActionBar().setDisplayHomeAsUpEnabled(true);
                        getActionBar().setTitle(gameObj.getGameName());
                        getActionBar().setSubtitle(gameObj.getSystemName());
                    }

                });
                try {
                    if (cm.getActiveNetworkInfo() != null) {
                        if (member == null) {
                            cheats = Webservice.getCheatList(gameObj, 0);
                        } else {
                            cheats = Webservice.getCheatList(gameObj, member.getMid());
                        }
                        cheatsArrayList = new ArrayList<Cheat>();

                        if (cheats != null) {
                            for (int j = 0; j < cheats.length; j++) {
                                cheatsArrayList.add(cheats[j]);
                            }
                        } else {
                            Log.e("CheatListActivity()", "Webservice.getCheatList() == null");
                        }

                        for (int i = 0; i < cheats.length; i++) {
                            Log.d("cheats", cheats[i].getCheatTitle());
                        }

                        gameObj.setCheats(cheats);

                        // Put game object to local storage for large games like
                        // Pokemon
                        editor.putString(Konstanten.PREFERENCES_TEMP_GAME_OBJECT_VIEW, new Gson().toJson(gameObj));
                        editor.commit();
                    } else {
                        Log.e("CheatTitleList:getCheats()", "No Network");
                        Toast.makeText(CheatListActivity.this, R.string.no_internet, Toast.LENGTH_SHORT).show();
                    }

                } catch (Exception ex) {
                    Log.e(getClass().getName(), "Error executing getCheats()", ex);
                }
            }
        }).start();

    }

    public Cheat[] getCheatsForFragment(final Intent intent) {

        gameObj = new Gson().fromJson(intent.getStringExtra("gameObj"), Game.class);

        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                getActionBar().setDisplayHomeAsUpEnabled(true);
                getActionBar().setTitle(gameObj.getGameName());
                getActionBar().setSubtitle(gameObj.getSystemName());
            }

        });

        try {
            if (cm.getActiveNetworkInfo() != null) {
                if (member == null) {
                    cheats = Webservice.getCheatList(gameObj, 0);
                } else {
                    cheats = Webservice.getCheatList(gameObj, member.getMid());
                }
                cheatsArrayList = new ArrayList<Cheat>();

                if (cheats != null) {
                    for (int j = 0; j < cheats.length; j++) {
                        cheatsArrayList.add(cheats[j]);
                    }
                } else {
                    Log.e("CheatListActivity()", "Webservice.getCheatList() == null");
                }

                for (int i = 0; i < cheats.length; i++) {
                    Log.d("cheats", cheats[i].getCheatTitle());
                }

                gameObj.setCheats(cheats);

                // Put game object to local storage for large games like Pokemon
                editor.putString(Konstanten.PREFERENCES_TEMP_GAME_OBJECT_VIEW, new Gson().toJson(gameObj));
                editor.commit();
            } else {
                Log.e("CheatTitleList:getCheats()", "No Network");
                Toast.makeText(this, R.string.no_internet, Toast.LENGTH_SHORT).show();
            }

        } catch (Exception ex) {
            Log.e(getClass().getName(), "Error executing getCheats()", ex);
        }

        return cheats;
    }

    /**
     * Callback method from {@link CheatListFragment.Callbacks} indicating that
     * the item with the given ID was selected.
     */
    @Override
    public void onItemSelected(int id) {
        if (mTwoPane) {
            // In two-pane mode, show the detail view in this activity by
            // adding or replacing the detail fragment using a
            // fragment transaction.

            visibleCheat = cheats[id];

            cheatForumFragment = new CheatForumFragment();
            cheatDetailMetaFragment = new CheatDetailMetaFragment();

            // VIEW FOR TABLETS
            Bundle arguments = new Bundle();
            arguments.putInt(CheatDetailTabletFragment.ARG_ITEM_ID, id);
            arguments.putString("cheatObj", new Gson().toJson(cheats[id]));
            arguments.putString("cheatForumFragment", new Gson().toJson(cheatForumFragment));
            arguments.putString("cheatDetailMetaFragment", new Gson().toJson(cheatDetailMetaFragment));

            cheatDetailFragment = new CheatDetailTabletFragment();
            cheatDetailFragment.setArguments(arguments);
            getSupportFragmentManager().beginTransaction().replace(R.id.cheat_detail_container, cheatDetailFragment).commit();

        } else {
            // In single-pane mode, simply start the detail activity
            // for the selected item ID.
            // Intent detailIntent = new Intent(this, YyyDetailActivity.class);
            // detailIntent.putExtra(YyyDetailFragment.ARG_ITEM_ID, id);
            // startActivity(detailIntent);

            editor.putInt(Konstanten.PREFERENCES_PAGE_SELECTED, id);
            editor.commit();

            // Using local Preferences to pass data for large game objects
            // (instead of intent) such as Pokemon
            Intent explicitIntent = new Intent(CheatListActivity.this, CheatViewPageIndicator.class);
            explicitIntent.putExtra("selectedPage", id);
            explicitIntent.putExtra("layoutResourceId", R.layout.activity_cheatview_pager);
            explicitIntent.putExtra("pageIndicatorColor", Konstanten.CYAN_DARK);
            startActivity(explicitIntent);

        }
    }   
}

以及 ListView 的 fragment 。

public class CheatListFragment extends ListFragment {

    /**
     * The serialization (saved instance state) Bundle key representing the
     * activated item position. Only used on tablets.
     */
    private static final String STATE_ACTIVATED_POSITION = "activated_position";

    /**
     * The fragment's current callback object, which is notified of list item
     * clicks.
     */
    private Callbacks mCallbacks = sDummyCallbacks;

    /**
     * The current activated item position. Only used on tablets.
     */
    private int mActivatedPosition = ListView.INVALID_POSITION;

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callbacks {
        /**
         * Callback for when an item has been selected.
         */
        public void onItemSelected(int position);
    }

    /**
     * A dummy implementation of the {@link Callbacks} interface that does
     * nothing. Used only when this fragment is not attached to an activity.
     */
    private static Callbacks sDummyCallbacks = new Callbacks() {
        @Override
        public void onItemSelected(int id) {
        }
    };


    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public CheatListFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        cheatListActivity = (CheatListActivity) getActivity();
        fontRoboto = Tools.getFontRobotoRegular(getActivity().getAssets());

        settings = cheatListActivity.getSharedPreferences(Konstanten.PREFERENCES_FILE, 0);

        gameObj = new Gson().fromJson(settings.getString(Konstanten.PREFERENCES_TEMP_GAME_OBJECT_VIEW, null), Game.class);

        if( gameObj == null) {
            new GetCheatsTask().execute(new Game());            
        } else {
            new GetCheatsTask().execute(gameObj);           
        }
    }

    private class GetCheatsTask extends AsyncTask<Game, Void, Void> {

        @Override
        protected Void doInBackground(Game... params) {

            if (params[0].getCheats() == null) {
                cheats = cheatListActivity.getCheatsForFragment(cheatListActivity.getIntent()); 
            } else {
                cheats = params[0].getCheats();
            }

            for (int i = 0; i < cheats.length; i++) {
                Log.d("Cheat Item ", cheats[i].getCheatTitle());
                cheatsArrayList.add(cheats[i]);
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            cheatAdapter = new CheatAdapter(getActivity(), R.layout.cheatlist_item, cheatsArrayList);
            setListAdapter(cheatAdapter);
        }
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Restore the previously serialized activated item position.
        if (savedInstanceState != null && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
            setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION));
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // Activities containing this fragment must implement its callbacks.
        if (!(activity instanceof Callbacks)) {
            throw new IllegalStateException("Activity must implement fragment's callbacks.");
        }

        mCallbacks = (Callbacks) activity;
    }

    @Override
    public void onDetach() {
        super.onDetach();

        // Reset the active callbacks interface to the dummy implementation.
        mCallbacks = sDummyCallbacks;
    }

    @Override
    public void onListItemClick(ListView listView, View view, int position, long id) {
        super.onListItemClick(listView, view, position, id);

        // Notify the active callbacks interface (the activity, if the
        // fragment is attached to one) that an item has been selected.
        // mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
        mCallbacks.onItemSelected(position);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mActivatedPosition != ListView.INVALID_POSITION) {
            // Serialize and persist the activated item position.
            outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
        }
    }

    /**
     * Turns on activate-on-click mode. When this mode is on, list items will be
     * given the 'activated' state when touched.
     */
    public void setActivateOnItemClick(boolean activateOnItemClick) {
        // When setting CHOICE_MODE_SINGLE, ListView will automatically
        // give items the 'activated' state when touched.
        getListView().setChoiceMode(activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
    }

    private void setActivatedPosition(int position) {
        if (position == ListView.INVALID_POSITION) {
            getListView().setItemChecked(mActivatedPosition, false);
        } else {
            getListView().setItemChecked(position, true);
        }

        mActivatedPosition = position;
    }

    private class CheatAdapter extends ArrayAdapter<Cheat> {

        private final ArrayList<Cheat> items;

        public CheatAdapter(Context context, int textViewResourceId, ArrayList<Cheat> items) {
            super(context, textViewResourceId, items);
            this.items = items;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.cheatlist_item, null);
            }

            try {
                Cheat cheat = items.get(position);
                if (cheat != null) {

                    TextView tt = (TextView) v.findViewById(R.id.game_title);
                    tt.setText(cheat.getCheatTitle());
                    tt.setTypeface(fontRoboto);

                    // Durchschnittsrating (nicht Member-Rating)
                    RatingBar ratingBar = (RatingBar) v.findViewById(R.id.small_ratingbar);
                    ratingBar.setNumStars(5);
                    ratingBar.setRating(cheat.getRatingAverage() / 2);

                    ImageView flag_newaddition = (ImageView) v.findViewById(R.id.newaddition);
                    if (cheat.getDayAge() < Konstanten.CHEAT_DAY_AGE_SHOW_NEWADDITION_ICON) {
                        flag_newaddition.setImageResource(R.drawable.flag_new);
                        flag_newaddition.setVisibility(View.VISIBLE);
                    } else {
                        flag_newaddition.setVisibility(View.GONE);
                    }

                    ImageView flag_screenshots = (ImageView) v.findViewById(R.id.screenshots);
                    if (cheat.isScreenshots()) {
                        flag_screenshots.setVisibility(View.VISIBLE);
                        flag_screenshots.setImageResource(R.drawable.flag_img);
                    } else {
                        flag_screenshots.setVisibility(View.GONE);
                    }

                    ImageView flag_german = (ImageView) v.findViewById(R.id.flag);
                    if (cheat.getLanguageId() == 2) { // 2 = Deutsch
                        flag_german.setVisibility(View.VISIBLE);
                        flag_german.setImageResource(R.drawable.flag_german);
                    } else {
                        flag_german.setVisibility(View.GONE);
                    }

                }
            } catch (Exception e) {
                Log.e(getClass().getName() + ".getView ERROR:", e.getMessage());
            }
            return v;
        }
    }
}

双 Pane 模式下的详细 View (在平板电脑上):

public class CheatDetailTabletFragment extends Fragment implements OnClickListener {
    /**
     * The fragment argument representing the item ID that this fragment
     * represents.
     */
    public static final String ARG_ITEM_ID = "item_id";

    /**
     * The dummy content this fragment is presenting.
     */
    private CheatContent.CheatItem mItem;
    private View rootView;

    /**
     * Mandatory empty constructor for the fragment manager to instantiate the
     * fragment (e.g. upon screen orientation changes).
     */
    public CheatDetailTabletFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ca = (CheatListActivity) getActivity();

        cheatTitleTypeface = Tools.getFontRobotoThin(getActivity().getAssets());
        cheatTextTypeface = Tools.getFontRobotoRegular(getActivity().getAssets());

        settings = getActivity().getSharedPreferences(Konstanten.PREFERENCES_FILE, 0);
        editor = settings.edit();

        if (getArguments().containsKey(ARG_ITEM_ID)) {
            // Load the dummy content specified by the fragment
            // arguments. In a real-world scenario, use a Loader
            // to load content from a content provider.

            mItem = CheatContent.ITEM_MAP.get(getArguments().getInt(ARG_ITEM_ID));
            cheatObj = new Gson().fromJson(getArguments().getString("cheatObj"), Cheat.class);

            cheatForumFragment = new Gson().fromJson(getArguments().getString("cheatForumFragment"), CheatForumFragment.class);
            cheatDetailMetaFragment = new Gson().fromJson(getArguments().getString("cheatDetailMetaFragment"), CheatDetailMetaFragment.class);
        }

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_cheat_detail, container, false);

        // ...

        // Show the dummy content as text in a TextView.
        if (mItem != null) {
            ((TextView) rootView.findViewById(R.id.text_cheat_before_table)).setText(mItem.getCheatTitle());
            ((TextView) rootView.findViewById(R.id.text_cheat_title)).setText(mItem.getCheatId());
        }

        // ...

        populateView();         

        return rootView;
    }

    /**
     * Create Layout
     */
    private void populateView() {
        // fills the view. no problems here.
    }

    /**
     * Populate Table Layout
     */
    private void fillTableContent() {
        // filling table content here. no problems here.
    }

    private void fillSimpleContent() {
        // filling with other content. works fine, too.
    }

}

单 Pane 模式下的详细 View (在手机上):

public class CheatViewPageIndicator extends FragmentActivity implements ReportCheatDialogListener, RateCheatDialogListener {

    // define variables...

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LayoutInflater inflater = LayoutInflater.from(this);
        intent = getIntent();

        viewLayout = inflater.inflate(intent.getIntExtra("layoutResourceId", R.layout.activity_cheatview_pager), null);
        setContentView(viewLayout);

        settings = getSharedPreferences(Konstanten.PREFERENCES_FILE, 0);
        editor = settings.edit();

        getActionBar().setHomeButtonEnabled(true);
        getActionBar().setDisplayHomeAsUpEnabled(true);

        try {
            gameObj = new Gson().fromJson(settings.getString(Konstanten.PREFERENCES_TEMP_GAME_OBJECT_VIEW, null), Game.class);
            if (gameObj == null) {
                gameObj = new Gson().fromJson(intent.getStringExtra("gameObj"), Game.class);
            }
            editor.putString(Konstanten.PREFERENCES_TEMP_GAME_OBJECT_VIEW, new Gson().toJson(gameObj));
            editor.commit();

            pageSelected = intent.getIntExtra("selectedPage", 0);
            activePage = pageSelected;
            pageIndicatorColor = intent.getIntExtra("pageIndicatorColor", Konstanten.CYAN_DARK);
            cheatObj = gameObj.getCheats();
            visibleCheat = cheatObj[pageSelected];

            getActionBar().setTitle(gameObj.getGameName());
            getActionBar().setSubtitle(gameObj.getSystemName());

            initialisePaging();
        } catch (Exception e) {
            Log.e(CheatViewPageIndicator.class.getName(), e.getMessage() + "");
        }

    }

    private void initialisePaging() {
        // ...
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.handset_cheatview_menu, menu);

        // Search
        getMenuInflater().inflate(R.menu.search_menu, menu);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

        return super.onCreateOptionsMenu(menu);
    }



    @Override
    protected void onResume() {
        super.onResume();
        invalidateOptionsMenu();
    }

    public ConnectivityManager getConnectivityManager() {
        if (cm == null) {
            cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        }
        return cm;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            // This ID represents the Home or Up button. In the case of this
            // activity, the Up button is shown. Use NavUtils to allow users
            // to navigate up one level in the application structure. For
            // more details, see the Navigation pattern on Android Design:
            //
            // http://developer.android.com/design/patterns/navigation.html#up-vs-back

            // onBackPressed();
            // return true;

            Intent upIntent = new Intent(this, CheatListActivity.class);
            NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // This activity is NOT part of this app's task, so create a new
                // task when navigating up, with a synthesized back stack.
                TaskStackBuilder.create(this)
                // Add all of this activity's parents to the back stack
                        .addNextIntentWithParentStack(upIntent)
                        // Navigate up to the closest parent
                        .startActivities();
            } else {
                // This activity is part of this app's task, so simply
                // navigate up to the logical parent activity.
                // NavUtils.navigateUpTo(this, upIntent);
                upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(upIntent);
                finish();
            }
            return true;
        }
        return super.onOptionsItemSelected(item);

    }       

}   

因此,在单 Pane 模式(在手机上)中,当我从 CheatViewPageIndicator.java 中单击操作栏中的“向上”按钮以获取 CheatListActivity.java 时,我得到一个指向此行的空指针异常:

gameObj = new Gson().fromJson(intent.getStringExtra("gameObj"), Game.class);    

返回时似乎“Intent ”为空。我想知道这是为什么?我需要做什么才能将数据保留在 Intent 中? (或任何其他如何摆脱空指针的解决方案对我来说也完全没问题)。我有点绝望,我一直在寻找解决方案太久了。

非常感谢您的帮助。

最佳答案

我通常使用另一种方式来指定父 Activity ,它在 list 文件中包含一个属性。

在CheatViewPageIndicator.java的activity标签中,添加这个属性:

 <activity
        ...
        android:parentActivityName="your.app.package.CheatListActivity" >
 </activity>   

并注释掉您为 upIntent 编写的所有行。这应该可以解决问题。

关于android - 在操作栏中单击 "up"时,主/详细流程中的 Intent 为空(空指针异常),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22337231/

有关android - 在操作栏中单击 "up"时,主/详细流程中的 Intent 为空(空指针异常)的更多相关文章

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

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

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  5. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  6. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  7. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  8. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  9. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  10. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

随机推荐