Вам нужно инициализировать @product. Это можно сделать так:
before_action :set_document, only: [:show, :edit, :update, :destroy]
def set_document
@document = Document.find(params[:id])
end
Вы можете пометить контроллер с помощью
rails g scaffold_controller Document
, чтобы увидеть, как именно rails генерирует классы для модели.
В вашем route.rb должно быть
resources: products
Хорошо, в первую очередь, Вы и создаете новый поток для своего кода сохранения и затем использования NSUrlConnection асинхронно. NSUrlConnection в его собственной реализации был бы также ответвление другой поток, и перезвоните Вам на своем недавно созданном потоке, который главным образом не является чем-то, что Вы пытаетесь сделать. Я предполагаю, что Вы просто пытаетесь удостовериться, что Ваш UI не блокируется, в то время как Вы сохраняете...
NSUrlConnection также имеет синхронную версию, которая заблокируется на Вашем потоке, и было бы лучше использовать это, если Вы хотите запустить свой собственный поток для того, чтобы сделать вещи. Подпись
+ sendSynchronousRequest:returningResponse:error:
Затем при возвращении ответа можно перезвонить в поток UI. Что-то как ниже должно работать:
- (void) beginSaving {
// This is your UI thread. Call this API from your UI.
// Below spins of another thread for the selector "save"
[NSThread detachNewThreadSelector:@selector(save:) toTarget:self withObject:nil];
}
- (void) save {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// ... calculate your post request...
// Initialize your NSUrlResponse and NSError
NSUrlConnection *conn = [NSUrlConnection sendSyncronousRequest:postRequest:&response error:&error];
// Above statement blocks until you get the response, but you are in another thread so you
// are not blocking UI.
// I am assuming you have a delegate with selector saveCommitted to be called back on the
// UI thread.
if ( [delegate_ respondsToSelector:@selector(saveCommitted)] ) {
// Make sure you are calling back your UI on the UI thread as below:
[delegate_ performSelectorOnMainThread:@selector(saveCommitted) withObject:nil waitUntilDone:NO];
}
[pool release];
}
Необходимо главным образом создать пул автовыпуска для потока. Попытайтесь изменить свой метод сохранения, чтобы быть похожими на это:
- (void) save:(id)arg {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Existing code
[pool drain];
}
Вы не будете Вы, что вышеупомянутое не называет выпуск на NSAutoreleasePool. Это - особый случай. Для NSAutoreleasePool дренаж эквивалентен для выпуска при выполнении без GC и преобразовывает в подсказку к коллектору, что это могла бы быть положительная сторона для выполнения набора.
Вы, возможно, должны создать цикл выполнения. Я добавлю к решению Louis:
BOOL done = NO;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSRunLoop currentRunLoop];
// Start the HTTP connection here. When it's completed,
// you could stop the run loop and then the thread will end.
do {
SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, YES);
if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished)) {
done = YES;
}
} while (!done);
[pool release];
В потоке необходимо создать новый пул автовыпуска, прежде чем Вы сделаете что угодно еще, иначе сетевые операции будут иметь проблемы, как Вы видели.
Я не вижу оснований для Вас для использования потоков для этого. Просто выполнение его асинхронно на цикле выполнения должно работать, не блокируя UI.
Доверие циклу выполнения. Это всегда легче, чем поточная обработка и разработано для обеспечения того же результата (никогда заблокированный UI).