2013-05-02 3 views
0

Я знаю, что это очень простой вопрос, но я думаю, что мой мозг и google-fu сегодня не работают так хорошо.Получить запись с url

Предположим, у меня есть событие с регистраторами, и они могут заплатить за мероприятие, используя один или несколько платежей.

Я пытаюсь создать платеж, связанный с регистрантом (кто связан с событием).
Так что мой платеж должен иметь как registrant_id, так и event_id.

Мой URL выглядит следующим образом: (вложенные маршруты)

http://mysite.com/events/1/registrants/1/payments/new 

Мой контроллер выглядит что-то вроде:

def create 
    @event = Event.find(params[:event_id]) 
    @registrant = Registrant.find(:first, conditions: {id: params[:registrant_id], event_id: params[:event_id]}) 

    @payment = Payment.new params[:payment] 
end 

Я знаю, что есть гораздо лучший способ сделать это, но У меня возникли проблемы с правильной формулировкой этого слова :)

Какой синтаксис я должен использовать для создания .new aut omatically известно о event_id и registrant_id?

+0

Вы имеете в виду, как передать в params [: event_id] и params [: registrant_id]? Если это так, вам нужно «def initialize event_id, registrant_id» в вашей платежной модели (или использовать хэш параметров и косвенно установить атрибуты). Или вы имеете в виду что-то еще? – Phil

+0

Неправильно ли устанавливать атрибуты id напрямую? Я могу просто добавить их в список 'attr_accessible', верно? –

+0

Если это только столбцы в таблице, вы можете просто установить их. Вероятно, вы захотите обратить внимание на свои определения внешнего ключа. Кроме того, как упоминает RobHeaton, идентификатор может фактически не существовать как строка базы данных, поэтому, как правило, если вы собираетесь создавать такие специальные ассоциации, как это, определите сначала объект (как вы это делаете), затем используйте атрибут registeristrant.id (вместо установки непосредственно из параметра). – Phil

ответ

0

на основе обсуждения в комментариях, есть несколько способов, что вопрос можно решить: прямой путь и путь Rails.

Прямой подход к созданию объектов, связанных с ними, заключается в создании объекта с использованием new_object = ClassName.new, как это было предложено в вопросе. Затем возьмите идентификатор созданного объекта и установите его на существующий объект (непосредственно с existing_object.id = new_object.id или с помощью какого-либо другого метода, если требуется дополнительная логика). Или установить идентификатор на новом объекте, определяя пользовательский инициализатору, такие как:

class Payment 
    def initializer id_of_registrant 
    @registrant_id = id_of_registrant 
    end 
... 
end 

Преимущества такого подхода заключается в том, что она позволяет назначать регистратор идентификаторов, которые могут возникнуть из ряда объектов с различными классами, без необходимости иметь ненужное или, возможно, неправильное (для вашего решения) наследование и полиморфизм.

Путь Rails, если вы всегда имеют прямое отношение (1 к 1) между регистраторами и «обязательной» Оплата является использование has_many или belongs_to ассоциации, как описано в руководстве Rails: http://guides.rubyonrails.org/association_basics.html

для примера классов от вопроса:

class Registrant < ActiveRecord::Base 
    has_one :payment 
end 

class Payment < ActiveRecord::Base 
    belongs_to :registrant 
end 

Вы хотите использовать соответствующую миграцию для создания таблиц базы данных и внешние ключи, которые идут с этим. Например:

class CreateRegistrants < ActiveRecord::Migration 
    def change 
    create_table :registrants do |t| 
     t.string :name 
     t.timestamps 
    end 

    create_table :payments do |t| 
     t.integer :registrant_id 
     t.string :account_number 
     t.timestamps 
    end 
    end 
end 

Конечно, если вы регистранты только при необходимости произвести оплату, или сделать несколько платежей, то вам нужно будет смотреть на использовании has_many ассоциации.

С имеют и принадлежит ассоциациям, вы можете делать хорошие вещи, как:

@payment.registrant = @registrant 

если вы инстанцированы объектам вручную или

@payment.new(payment_amount) 
@registrant = @payment.build_registrant(:registrant_number => 123, 
    :registrant_name => "John Doe") 

, если вы хотите ассоциации заселены автоматически.

В Rails Guide есть много примеров, хотя, по моему опыту, только попытка найти наиболее подходящую для вашего фактического варианта использования покажет, есть ли ограничения, которых нельзя было ожидать. Подход Rails упростит будущие запросы и создание объектов, но если у вас есть очень свободная модель отношений для ваших объектов, вы можете обнаружить, что она становится ограничительной или неестественной, и эквивалентные ассоциации лучше кодируются вручную с помощью ваших дополнительных бизнес-правил.

+0

Ваш ответ указал мне в правильном направлении. Возвращаясь к основам ассоциаций в руководствах Rails, я добрался до того места, где мне нужно быть. Я могу использовать '@payment = @ registrant.payments.new (payment_details)' и использовать '@ payment.registrant.event.id', чтобы получить event_id. Но я чувствую, что должен быть способ сделать просто '@ payment.event.id'. Когда я использую этот метод, событие 'event_id' не сохраняется в платеже. –

+0

ОК, я думаю, я вижу, что вы говорите. Мой вопрос таков: какие объектные отношения вы хотите? Я предполагаю, что событие имеет несколько регистраторов, каждый из которых имеет ноль или более платежей за событие.Может ли регистратор быть связан с несколькими событиями? Если это так, тогда вам нужно будет указать идентификатор события во время создания платежа регистрантом. 'payment.event_id' должен работать нормально, чтобы установить это (в инициализаторе), если вы не забыли сохранить изменения. Платеж также должен иметь ассоциацию belongs_to с событием. – Phil

+0

О, человек. Почему-то я забыл добавить в свой класс Payment 'belongs_to: event'. Теперь работает '@ payment.event'. –

0

Неправильно установить атрибуты id, так как идентификатор может не ссылаться на фактическую строку базы данных. Обычным делом здесь было бы использовать CanCan (https://github.com/ryanb/cancan), который, похоже, решит все ваши проблемы.

EDIT:

Если вы не используете проверку подлинности любого рода, то я бы либо поставить методы нагрузки в before_filter с, чтобы держать вещи в чистоте:

before_filter :load_event 

def load_event 
    @event = Event.find params[:event_id] 
end 

или определить некоторые фанки общий загрузчик (излишне мета- и сложный и не рекомендуется):

_load_resource :event 

def self._load_resource resource_type 
    before_filter do 
    resource = resource_type.constantize.find params[:"#{ resource_type }_id] 
    instance_variable_set :"@#{ resource_type }", resource 
    end 
end 
+0

Спасибо за подсказку, но cancan для пользователей. Мое приложение предназначено для администрирования. Платежи будут поступать от имени клиентов. –

+0

Если вы вошли в систему как администратор (поэтому существует 'current_user'), вы можете просто определить свои разрешения соответственно, например. может создать платеж, если это admin. – RobHeaton

+0

Планируется вообще не добавлять аутентификацию. –

Смежные вопросы