我从服务器下载数据并用它们填充 ListView 。 ListView 中的每个项目都有 3 个按钮,我想在每个按钮上创建一个 onclicklistener。当用户单击其中一个按钮时,它应该例如打开新 Activity 。每行(对象)都有一些 id,当我点击其中一些按钮时,id 总是例如 15(它总是 listview 中最后一行的 id)。 我尝试过用许多不同的方式声明 OnClickListeners,结果都是一样的。
法律适配器
public class LawsAdapter extends ArrayAdapter<Law> implements View.OnClickListener {
private LayoutInflater inflater;
private Context context;
private UserLocalStore userLocalStore;
private IsVotedStorage isVotedStorage;
private View convertView;
private ViewHolder viewHolder;
/**
* Constructor, declares storages, context and inflater
* @param context
* @param textViewResourceId
*/
public LawsAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
this.context = context;
inflater = ((Activity) context).getLayoutInflater();
userLocalStore = new UserLocalStore(context);
isVotedStorage = new IsVotedStorage(context);
}
/**
* Second constructor, here you can set the resource (againstr the previous one)
* @param context
* @param resource
* @param items
*/
public LawsAdapter(Context context, int resource, List<Law> items) {
super(context, resource, items);
this.context = context;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
userLocalStore = new UserLocalStore(context);
isVotedStorage = new IsVotedStorage(context);
}
/**
* Overriden method getView, declares graphic objects (btns... ) and set listeners
* @param position
* @param convertView
* @param parent
* @return view
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.law_item, parent, false);
this.convertView = convertView;
viewHolder = new ViewHolder();
viewHolder.tvName = (TextView) convertView.findViewById(R.id.lawItemName);
viewHolder.tvDescription = (TextView) convertView.findViewById(R.id.lawItemDescription);
viewHolder.tvStatus = (TextView) convertView.findViewById(R.id.lawItemStatus);
viewHolder.btnDownvote = (Button) convertView.findViewById(R.id.lawItemDownvote);
viewHolder.btnUpvote = (Button) convertView.findViewById(R.id.lawItemUpvote);
viewHolder.btnMakeComment = (Button) convertView.findViewById(R.id.lawItemMakeComment);
viewHolder.currentLaw = getItem(position);
Log.d("View holder", "new one");
Log.d("LAW ID, ADAPTER", String.valueOf(viewHolder.currentLaw.getId()));
viewHolder.tvName.setText(viewHolder.currentLaw.getName());
viewHolder.tvDescription.setText(viewHolder.currentLaw.getDescription());
viewHolder.tvStatus.setText(viewHolder.currentLaw.getStateValue());
setSurfacesColors();
viewHolder.btnMakeComment.setOnClickListener(this);
viewHolder.btnDownvote.setOnClickListener(this);
viewHolder.btnUpvote.setOnClickListener(this);
disableIfVoted();
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
Log.d("View holder", "get tag");
}
return convertView;
}
/**
* Set the colors of surfaces
*/
private void setSurfacesColors() {
viewHolder.sfLeft = (SurfaceView) convertView.findViewById(R.id.lawItemSurfaceLeft);
viewHolder.sfBackground = (SurfaceView) convertView.findViewById(R.id.lawItemSurfaceBackground);
Log.d("VOTES", "Positive: " + viewHolder.currentLaw.getPositiveVotes() + " Negative: " + viewHolder.currentLaw.getNegativeVotes());
if ((viewHolder.currentLaw.getNegativePercent() + viewHolder.currentLaw.getNegativeVotes()) > 1) {
viewHolder.sfBackground.setBackgroundColor(context.getResources().getColor(R.color.redSurfaceBckg));
viewHolder.sfLeft.setBackgroundColor(context.getResources().getColor(R.color.btnSubmitColor));
int screenWidth = getScreenWidth();
int upvote = viewHolder.currentLaw.getNegativePercent();
int downvote = viewHolder.currentLaw.getPositivePercent();
int positivePixels = (screenWidth / 100) * upvote;
int negativePixels = (screenWidth / 100) * downvote;
viewHolder.sfBackground.getHolder().setFixedSize(negativePixels, 5);
viewHolder.sfLeft.getHolder().setFixedSize(positivePixels, 5);
Log.d("UPDATE", "NOTIFY");
}
else {
viewHolder.sfBackground.setBackgroundColor(context.getResources().getColor(R.color.greySurface));
viewHolder.sfLeft.setBackgroundColor(context.getResources().getColor(R.color.greySurface));
}
}
/**
* Upvote
* @param law
*/
private void upvote(Law law) {
ServerRequest serverRequest = new ServerRequest(context);
serverRequest.upvoteLawInBackground(law.getId(), new UpDownCallback() {
@Override
public void done(Law law) {
viewHolder.currentLaw = law;
setSurfacesColors();
Log.e("VOTES in UPVOTE", "Positive: " + viewHolder.currentLaw.getPositiveVotes() + " Negative: " + viewHolder.currentLaw.getNegativeVotes());
}
});
}
/**
* Downvote
* @param law
*/
private void downvote(Law law) {
ServerRequest serverRequest = new ServerRequest(context);
serverRequest.downvoteLawInBackground(law.getId(), new UpDownCallback() {
@Override
public void done(Law law) {
viewHolder.currentLaw = law;
setSurfacesColors();
}
});
}
/**
* Get screen width in pixels
* @return int screen width
*/
private int getScreenWidth() {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
return width;
}
/**
* Disable voting button if I have already voted
*/
private void disableIfVoted() {
if (isVotedStorage.isVoted(viewHolder.currentLaw.getId())) {
viewHolder.btnUpvote.setEnabled(false);
viewHolder.btnDownvote.setEnabled(false);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.lawItemMakeComment:
if (userLocalStore.isUserLoggedIn()) {
Log.d("ON CLICK LAW ID", String.valueOf(viewHolder.currentLaw.getId()));
Intent commentsIntent = new Intent(context, DialogCommentsActivity.class);
commentsIntent.putExtra("law_id", viewHolder.currentLaw.getId());
commentsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Log.d("CURRENT LAW", viewHolder.currentLaw.getId() + " " + viewHolder.currentLaw.getName());
context.startActivity(commentsIntent);
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
break;
case R.id.lawItemDownvote:
if (userLocalStore.isUserLoggedIn()) {
isVotedStorage.setVoted(true, viewHolder.currentLaw.getId());
downvote(viewHolder.currentLaw);
disableIfVoted();
notifyDataSetChanged();
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
break;
case R.id.lawItemUpvote:
if (userLocalStore.isUserLoggedIn()) {
isVotedStorage.setVoted(true, viewHolder.currentLaw.getId());
upvote(viewHolder.currentLaw);
disableIfVoted();
notifyDataSetChanged();
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
break;
}
}
/**
* Holds items per row
*/
private static class ViewHolder {
private TextView tvName;
private TextView tvDescription;
private TextView tvStatus;
private Button btnUpvote;
private Button btnDownvote;
private Button btnMakeComment;
private SurfaceView sfBackground;
private SurfaceView sfLeft;
private Law currentLaw;
}
law_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="170dp"
android:gravity="bottom"
android:padding="6pt"
android:background="@color/button_material_light">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="140dp"
android:gravity="bottom"
android:background="@color/background_floating_material_light"
android:theme="@style/AppTheme"
android:id="@+id/rel">
<SurfaceView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lawItemSurfaceBackground"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<SurfaceView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/lawItemSurfaceLeft"
android:layout_alignBaseline="@+id/lawItemSurfaceBackground"
android:layout_alignBottom="@+id/lawItemSurfaceBackground"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lawItemName"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_below="@+id/lawItemSurfaceBackground"
android:layout_marginTop="2pt"
android:layout_marginBottom="3pt"
android:layout_marginLeft="3pt"
android:layout_marginRight="3pt"
android:padding="1pt"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lawItemName"
android:textAppearance="?android:attr/textAppearanceMedium"
android:padding="1pt"
android:layout_marginLeft="3pt"
android:layout_marginRight="3pt"
android:layout_marginBottom="3pt"
android:id="@+id/lawItemDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="1pt"
android:layout_marginBottom="3pt"
android:id="@+id/lawItemStatus"
android:layout_marginRight="30pt"
android:layout_below="@+id/lawItemDescription"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_below="@id/lawItemStatus"
android:orientation="horizontal">
<Button android:layout_weight="1"
android:layout_height="wrap_content"
android:background="@color/btnSubmitColor"
android:textColor="@color/btnSubmitTextColor"
android:layout_width="match_parent"
android:focusable="false"
android:text="@string/button_upvote"
android:id="@+id/lawItemUpvote" />
<Button android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="@color/btnSubmitColor"
android:textColor="@color/btnSubmitTextColor"
android:text="@string/button_downvote"
android:focusable="false"
android:id="@+id/lawItemDownvote" />
<Button android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="@color/btnSubmitColor"
android:textColor="@color/btnSubmitTextColor"
android:focusable="false"
android:text="@string/button_comment"
android:id="@+id/lawItemMakeComment" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
示例:我点击第一行的 btnMakeComment,新的 Activity 打开并从 id 为 15 的对象的 db comments 下载。然后我点击第三行的 btnMakeComment,新的 Activity 打开并从 db comments 下载具有相同 id 的对象,就像上次一样(又是 15)。 但是在 ListView 中不是相同的行/对象,它们只是在单击时不同,看起来它们是相同的。
DialogCommentsActivity
/**
* Activity for adding and reading comments
*/
public class DialogCommentsActivity extends AppCompatActivity implements AbsListView.OnItemClickListener, AbsListView.OnScrollListener, View.OnClickListener {
private int lawId;
private int limit;
private int offset;
private int preLast;
private int page;
private ListView listView;
private EditText etAddComment;
private List<Comment> activityCommentList;
private UserLocalStore userLocalStore;
private User user;
private Button btnSubmit;
private CommentsAdapter commentsAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comments_dialog);
setTitle("");
setFinishOnTouchOutside(true);
listView = (ListView) findViewById(R.id.commentDialogListView);
limit = 5;
offset = 0;
page = 1;
userLocalStore = new UserLocalStore(this);
user = userLocalStore.getLoggedUser();
etAddComment = (EditText) findViewById(R.id.commentDialogEditAdd);
btnSubmit = (Button) findViewById(R.id.commentsDialogSubmit);
btnSubmit.setEnabled(false);
listView.setOnItemClickListener(this);
listView.setOnScrollListener(this);
btnSubmit.setOnClickListener(this);
Bundle extras = getIntent().getExtras();
String userName;
dumpIntent(getIntent());
if (extras != null) {
lawId = extras.getInt("law_id");
}
Log.e("LAW ID HOHOHO", String.valueOf(lawId));
fillAdapter(limit, offset);
etAddComment.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().trim().length() == 0) {
btnSubmit.setEnabled(false);
} else {
btnSubmit.setEnabled(true);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_detail_law, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
switch(listView.getId()) {
case R.id.commentDialogListView:
Log.d("SCROLL", "scroll");
boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount-1;
if (loadMore) {
page += 1;
// offset = (page * limit) - limit + 1;
// fillAdapter(limit, offset);
// commentsAdapter.notifyDataSetChanged(); TODO
}
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
public void fillAdapter(int limit, int offset) {
ServerRequest serverRequest = new ServerRequest(this);
Log.e("LAWID BEFORE REQUEST", String.valueOf(lawId));
serverRequest.fetchCommentsInBackground(lawId, limit, offset, new GetCommentsCallback() {
@Override
public void done(List<Comment> comments) {
commentsAdapter = new CommentsAdapter(getApplicationContext(), R.layout.comment_item, comments);
listView.setAdapter(commentsAdapter);
activityCommentList = commentsAdapter.getList();
}
});
}
public void loadData(int limit, int offset) {
ServerRequest serverRequest = new ServerRequest(this);
Log.e("LAWID BEFORE REQUEST", String.valueOf(lawId));
serverRequest.fetchCommentsInBackground(lawId, limit, offset, new GetCommentsCallback() {
@Override
public void done(List<Comment> comments) {
// Updating parsed JSON data into ListView
for (Comment comment : comments) {
Log.d("COMMENT OBJECT", comment.getText());
activityCommentList.add(comment);
}
}
});
}
/**
* Handle click events, comments adding
* @param v
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.commentsDialogSubmit:
String text = String.valueOf(etAddComment.getText());
Date dt = new Date();
Log.d("Click", "Click");
if (userLocalStore.isUserLoggedIn()) {
Log.e("LAW ID NEW COMM", String.valueOf(lawId));
Comment comment = new Comment(text, dt, user, lawId);
addComment(comment);
etAddComment.setText("");
//notifyData(limit, offset);
limit = 15;
offset = 0;
fillAdapter(limit, offset);
commentsAdapter.notifyDataSetChanged();
Log.e("NUMBER OF COMMENTS", String.valueOf(activityCommentList.size()));
}
break;
}
}
/**
* Insert comment
* @param comment
*/
public void addComment(Comment comment) {
ServerRequest serverRequest = new ServerRequest(this);
serverRequest.storeCommentInBackground(comment, new GetCommentsCallback() {
@Override
public void done(List<Comment> list) {
Log.d("Comment", "Comment was added.");
}
});
}
private void dumpIntent(Intent i) {
Bundle bundle = i.getExtras();
if (bundle != null) {
Set<String> keys = bundle.keySet();
Iterator<String> it = keys.iterator();
Log.e("EXTRAS", "Dumping Intent start");
while (it.hasNext()) {
String key = it.next();
Log.e("EXTRAS", "[" + key + "=" + bundle.get(key) + "]");
}
Log.e("EXTRAS", "Dumping Intent end");
}
}
}
解决方案:
我添加了 ViewHolder viewHolder = v.getTag();在每个监听器中(以及在它之前在每个按钮上的 getView 中设置标签(viewHolder)
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.law_item, parent, false);
this.convertView = convertView;
viewHolder = new ViewHolder();
viewHolder.position = position;
viewHolder.tvName = (TextView) convertView.findViewById(R.id.lawItemName);
viewHolder.tvDescription = (TextView) convertView.findViewById(R.id.lawItemDescription);
viewHolder.tvStatus = (TextView) convertView.findViewById(R.id.lawItemStatus);
viewHolder.btnDownvote = (Button) convertView.findViewById(R.id.lawItemDownvote);
viewHolder.btnUpvote = (Button) convertView.findViewById(R.id.lawItemUpvote);
viewHolder.btnMakeComment = (Button) convertView.findViewById(R.id.lawItemMakeComment);
viewHolder.btnMakeComment.setTag(viewHolder);
viewHolder.btnDownvote.setTag(viewHolder);
viewHolder.btnUpvote.setTag(viewHolder);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
Log.d("View holder", "get tag");
}
viewHolder.currentLaw = getItem(position);
Log.d("View holder", "new one");
Log.d("LAW ID, ADAPTER", String.valueOf(viewHolder.currentLaw.getId()));
viewHolder.tvName.setText(viewHolder.currentLaw.getName());
viewHolder.tvDescription.setText(viewHolder.currentLaw.getDescription());
viewHolder.tvStatus.setText(viewHolder.currentLaw.getStateValue());
setSurfacesColors();
disableIfVoted();
viewHolder.btnMakeComment.setOnClickListener(onCommentClickListener);
viewHolder.btnDownvote.setOnClickListener(onDowvnvoteClickListener);
viewHolder.btnUpvote.setOnClickListener(onUpvoteClickListener);
// viewHolder.btnMakeComment.setOnClickListener(onCommentClickListener);
return convertView;
}
@Override
public long getItemId(int position) {
return laws.get(position).getId();
}
@Override
public Law getItem(int position) {
return laws.get(position);
}
/**
* On upvote listener
*/
private View.OnClickListener onUpvoteClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHolder viewHolder = (ViewHolder) v.getTag();
if (userLocalStore.isUserLoggedIn()) {
isVotedStorage.setVoted(true, viewHolder.currentLaw.getId());
upvote(viewHolder.currentLaw);
disableIfVoted();
notifyDataSetChanged();
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
}
};
/**
* On downvote listener
*/
private View.OnClickListener onDowvnvoteClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHolder viewHolder = (ViewHolder) v.getTag();
if (userLocalStore.isUserLoggedIn()) {
isVotedStorage.setVoted(true, viewHolder.currentLaw.getId());
downvote(viewHolder.currentLaw);
disableIfVoted();
notifyDataSetChanged();
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
}
};
/**
* On comment listener, open comment dialog
*/
private View.OnClickListener onCommentClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
ViewHolder viewHolder = (ViewHolder) v.getTag();
if (userLocalStore.isUserLoggedIn()) {
Log.d("ON CLICK LAW ID", String.valueOf(viewHolder.currentLaw.getId()));
Intent commentsIntent = new Intent(context, DialogCommentsActivity.class);
commentsIntent.putExtra("law_id", viewHolder.currentLaw.getId());
commentsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Log.d("CURRENT LAW", viewHolder.currentLaw.getId() + " " + viewHolder.currentLaw.getName());
context.startActivity(commentsIntent);
} else {
context.startActivity(new Intent(context, DialogSignInActivity.class));
}
}
};
最佳答案
你每次都得到最后一个 id/最后一行位置,因为最后一个 View 最后 reders
要获取按钮点击时的行位置,您可以将 position 设置为按钮的标签,并检查 onclickListner 中的标签
例如,在您的 getview() 方法中,将位置作为标记放入 viewHolder.btnMakeComment 按钮中
viewHolder.btnMakeComment.setTag(position); 并在OnClickListner 检查标签
int position = (int)v.getTag();
关于android - ListView 项中的 OnClickListener 始终占用最后一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32284979/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我试图在一个项目中使用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时
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
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上找到一个类似的问题
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>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
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA