2013-12-15 2 views
5

У меня есть фон программирования C, и я изучаю Ruby/Rails для побочного проекта. В настоящее время я изо всех сил пытаюсь понять, как работает область видимости переменных. Вот пример проблемы, с которой я сталкиваюсь. У меня есть модель User и Product. В БД продукта я храню разные продукты, и одно из полей - это поле userid, которое соответствует идентификатору пользователя, хранящемуся в таблице User. После входа пользователя в систему - я показываю имя пользователя, адрес электронной почты и т. Д. (Это сохраняется в @current_user), а затем имеет ссылку для отображения разных продуктов, принадлежащих пользователю. Я делаю это с помощью следующего кода пользователей/show.html.erb как это: ... Доступ к одной переменной контроллера в другом контроллере в Rails

Имя: <% = @ current_user.name%>

... <% = link_to «Продукты», products_path, id: «продукты»%>

Пока все хорошо. Когда я нажимаю ссылку «Продукты», она принимает меня к продуктам/index.html.erb, и следующий код запускается (я хочу отфильтровать этот показ, чтобы показывать только продукты, принадлежащие @ current_user.userid. Как это сделать? следующий код дает мне ошибку времени выполнения, как @current_user оценивает всухую я считаю. Если удалить «если» пунктом, то все продукты ар отображается, которые не то, что я хочу. Был бы признателен за любые советы.

<tbody> 
<% @products.each do |product| %> 
    <tr> 
    <td><%= product.userid if product.userid == @current_user.userid %></td> 
    <td><%= product.productName if product.userid == @current_user.userid %></td> 
    <td><%= product.productLink if product.userid == @current_user.userid %></td> 

Спасибо,

+1

Предлагаю вам изучить драгоценный камень. Без этого добавьте вспомогательный метод приложения 'current_user', который извлекает пользователя (и запоминает результат). Devise - очень популярный камень, используемый в большинстве проектов Rails. Но если вам нравится, я могу создать ответ с помощью ручного метода. –

ответ

10

Я собирался сделать этот комментарий, но я думаю, что он заслуживает ответа. Дело в том, чтобы понять не только рельсы, но и все интернеты, это то, что HTTP является апатридом. Это означает, что в вашем контроллере вы захватываете информацию пользователя, создаете им веб-страницу со всеми их материалами из базы данных и отправляете их им. Затем они делают что-то на странице и отправляют запрос на другую страницу или больше данных, а ваше приложение для рельсов похоже на «О, хай! Кто ты?» Потому что все те переменные, которые вы заполняли хорошей информацией, просто исчезли. Каждый раз, когда ваше приложение получает запрос, оно делает совершенно новый экземпляр используемого им контроллера, а затем избавляется от него, а также все внутри него. И это важно, потому что в вашем последнем веб-сайте лиги фризби могут быть тысячи или миллионы людей, которые пытаются выяснить, кто играет там, где в субботу. И вы хотите дать правильную информацию правильному человеку, вы не можете предположить, что человек, которого вы отправили ранее, является тем же самым человеком, который просит вас получить новую информацию.

Таким образом, нам нужно использовать session, некоторую информацию, которая передается браузеру браузера при каждой отправке страницы, и браузер отправляет ее обратно вам с каждым запросом. Вы помещаете достаточно информации в сеанс, чтобы вы могли использовать его для восстановления того, что вам нужно с сервера, когда вы получите ответ. Я собираюсь сделать это очень простым, а затем отсылаю вас к Rails Security Guide, где вы можете получить более важную информацию.На самом деле, я просто использовать свой пример:

Вы можете добавить идентификатор пользователя в сессии так:

session[:user_id] = @current_user.id 

А потом получить его обратно так:

@current_user = User.find(session[:user_id]) 

А потом вы используете свою модель пользователя (в данном случае), чтобы получить нужную информацию из базы данных. Вот еще одна ссылка на Rails Guides, потому что это так хорошо, я связав его дважды: http://guides.rubyonrails.org/security.html#what-are-sessions-questionmark

Если вы делаете что-то, что требует пароль, то можете использовать камень как devise, instructions here, но имейте в виду, это полностью перехватывает ваша модель пользователя, контроллер сеансов, некоторые представления, в основном все, что связано с входом в систему и идентификацией. Это непросто настроить, но это делает все эти вещи и вещи намного сложнее, очень просто реализовать. Если вам не нужны никакие имена пользователей или пароли, и вы делаете что-то реальное просто, просто пропустите специальные драгоценные камни и используйте сеанс самостоятельно.

0

Вы должны инициализировать @current_user на каждом запросе, а не только после входа пользователя в систему. переменные экземпляра контроллера не сохраняются между запросами.

Вот общий способ для этого:

  1. Сохраните идентификатор пользователя в сеансе.
  2. Создайте фильтр «before» в ApplicationController, который извлекает идентификатор пользователя из сеанса и инициализирует переменную экземпляра.
0

Невозможно получить доступ к переменной экземпляра в одном действии в другом действии. Как уже упоминалось, вам нужно будет сохранить user_id в сеансе хэша. В контроллере, который обрабатывает ваш пользовательский sign_in, вы должны сделать что-то вроде этого:

#in SessionsController(for example) 

def create 
    user = User.find_by(email: params[:session][:email].downcase) 
    if user && user.authenticate # logic for authentication 
    session[:user_id] = user.id 
    redirect_to root_path, notice: "Successful sign in." 
    else 
    flash.now[:error] = "Invalid email/password combination" 
    render :new 
    end 
end 

принять к сведению присвоение user_id к ключу сеанса: user_id в хэш сессии. Теперь, в application_helper или sessions_helper определяют current_user так, чтобы она была доступна для всех просмотров:

def current_user 
    User.find(session[:user_id]) if session[:user_id] 
end 

Теперь перебрать все продукты определенного пользователя в:

<tbody> 
<% current_user.products.each do |product| %> 
    <tr> 
    <td><%= product.userid %></td> 
    <td><%= product.product_name %></td> 
    <td><%= product.product_link %></td> 

До тех пор, пока у вас есть has_many :products ассоциации в Модель пользователя и продукта имеет belongs_to :user, вы должны иметь возможность звонить всем пользовательским продуктам, просто делая user.products, как указано выше. Также обратите внимание, что я использовал «snake_case» для методов/атрибутов продукта. Это соглашение в Ruby для использования snake_case для имен и переменных методов. Если вы назвали свои столбцы productName и productLink, вам придется их переименовать, чтобы иметь возможность использовать 'snake_case'. В Ruby CamelCase используется для Class и ModuleNames.

Надеюсь, что это поможет!

+0

Спасибо за все информативные комментарии, каждый из которых был абсолютно полезен - я узнал несколько новых вещей в этой теме, мальчик, этот мир веб-разработки настолько отличается от того, к чему я привык! После прочтения этой темы я смог сделать то, что хотел. Я застрял несколько раз, но нашел свой путь с Google. Слишком много о рельсах, похоже, черная магия. – user3079275

+0

Замечательно, что мои комментарии помогли! Вы правы, чтобы думать о том, что Rails делает много черной магии. Это огромная структура, и для удобства она упрощает сделку. Если вы придерживаетесь своих соглашений, то вы обнаружите, что будете более продуктивными. Я предлагаю документацию тем временем. Как только у вас будет хорошее заземление в Ruby, его метапрограммирующие трюки и публичный API Rails, вы можете в конечном итоге погрузиться в его источник, чтобы узнать, как он это делает. – Gjaldon

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