【问题标题】:ruby on rails has_many through relationshipruby on rails has_many 通过关系
【发布时间】:2012-06-12 23:04:17
【问题描述】:

您好,我的应用程序的 has_many through 关系有点麻烦,希望能找到一些帮助。所以我有用户和讲座。讲座由一位用户创建,但随后其他用户可以“加入”已创建的讲座。用户有他们自己创建的讲座的个人资料提要,也有朋友创建的讲座的提要。然而,这个问题不是关于创建讲座,而是“加入”已经创建的讲座。我创建了一个“lecturerelationships”模型和控制器来处理 Lectures 和已加入的用户(我称之为“活动”)之间的这种关系。用户还必须“退出”讲座(通过单击“退出”或导航到标题导航链接之一)。如果有人可以和我一起解决其中的一些问题,我将不胜感激......

我有: 用户.rb 模型 Lectures.rb 模型 用户控制器 Lectures_controller

那么下面的模型

lecturerelationship.rb

class lecturerelationship < ActiveRecord::Base
  attr_accessible :active_id, :joinedlecture_id

  belongs_to :active, :class_name => "User"
  belongs_to :joinedlecture, :class_name => "Lecture"

  validates :active_id, :presence => true
  validates :joinedlecture_id, :presence => true

end

lecturerelationships_controller.rb

class LecturerelationshipsController < ApplicationController
  before_filter :signed_in_user

  def create
   @lecture = Lecture.find(params[:lecturerelationship][:joinedlecture_id])
   current_user.join!(@lecture)
   redirect_to @lecture
  end

 def destroy
  @lecture = Lecturerelationship.find(params[:id]).joinedlecture
  current_user.exit!(@user)
  redirect_to @user
 end

end

已(由朋友)创建的讲座会显示在以下文件中的用户供稿中

_activity_item.html.erb

<li id="<%= activity_item.id %>">
  <%= link_to gravatar_for(activity_item.user, :size => 200), activity_item.user %><br   clear="all">
  <%= render :partial => 'shared/join', :locals => {:activity_item => activity_item} %>
  <span class="title"><%= link_to activity_item.title, lecture_url(activity_item)  %></span><br clear="all">
  <span class="user">
   Joined by <%= link_to activity_item.user.name, activity_item.user %>
  </span><br clear="all">
  <span class="timestamp">
   <%= time_ago_in_words(activity_item.created_at) %> ago.
  </span>
  <% if current_user?(activity_item.user) %>
    <%= link_to "delete", activity_item, :method => :delete,
                                     :confirm => "Are you sure?",
                                     :title => activity_item.content %>
  <% end %>
</li>

然后你会看到我链接到上面的“共享/加入”部分,可以在下面的文件中看到

_join.html.erb

<%= form_for(current_user.lecturerelationships.build(:joinedlecture_id =>  activity_item.id)) do |f| %>
  <div>
   <%= f.hidden_field :joinedlecture_id %>
  </div>
  <%= f.submit "Join", :class => "btn btn-large btn-info" %>
<% end %>

可能需要的更多文件:

config/routes.rb

SampleApp::Application.routes.draw do
  resources :users do
    member do
    get :following, :followers, :joined_lectures
  end
end

resources :sessions, :only => [:new, :create, :destroy]
resources :lectures, :only  => [:create, :destroy, :show]
resources :relationships, :only => [:create, :destroy] #for users following each other
resources :lecturerelationships, :only => [:create, :destroy] #users joining existing lectures

所以发生的情况是讲座出现在我的 activity_feed 中,底部有一个加入按钮选项......这应该创建一个“活动”和“joinedlecture”的讲座关系(显然应该来自用户&讲座课程。但是当我点击加入按钮时我得到的错误如下:

ActiveRecord::StatementInvalid in LecturerelationshipsController#create

SQLite3::ConstraintException: constraint failed: INSERT INTO "lecturerelationships"     ("active_id", "created_at", "joinedlecture_id", "updated_at") VALUES (?, ?, ?, ?)

我还包括了我的用户模型(似乎错误是指它) 用户.rb

class User < ActiveRecord::Base
  attr_accessible :email, :name, :password, :password_confirmation
  has_secure_password
  has_many :lectures, :dependent => :destroy


  has_many :lecturerelationships, :foreign_key => "active_id", :dependent => :destroy
  has_many :joined_lectures, :through => :lecturerelationships, :source =>    :joinedlecture

  before_save { |user| user.email = email.downcase }
  before_save :create_remember_token

  validates :name, :presence => true, :length => { :maximum => 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, :presence => true,
        :format => { :with => VALID_EMAIL_REGEX },
        :uniqueness => { :case_sensitive => false }
  validates :password, :presence => true, :length => { :minimum => 6 }
  validates :password_confirmation, :presence => true

  def activity
    # This feed is for "My Activity" - basically lectures i've started
    Lecture.where("user_id = ?", id)
  end

  def friendactivity
     Lecture.from_users_followed_by(self)
  end

  # lECTURE TO USER (JOINING) RELATIONSHIPS
  def joined?(selected_lecture)
    lecturerelationships.find_by_joinedlecture_id(selected_lecture.id)
  end

  def join!(selected_lecture)
    lecturerelationships.create!(:joinedlecture_id => selected_lecture.id)
  end

  def exit!(selected_lecture)
   lecturerelationships.find_by_joinedlecture_id(selected_lecture.id).destroy
  end


end

感谢您提供的所有帮助 - 我会在这里待一段时间,如前所述,我非常感谢可能有时间与我一起解决问题的人...

【问题讨论】:

  • 一方面,您可能会通过更短的变量名获得更愉快的 Rails 体验。一个大问题是您的创建操作应该从 Lecture 表而不是 User 表中检索数据。
  • 感谢 cdesrosiers - 这是我完全忽略的东西。我已经更新了上面的那部分。但现在我得到一个新的错误,我现在正在添加
  • 正确的乔丹,我正在尝试创建一个joinedlecture_id(基于常规讲座课程),其中包含很多“actives_id”(已加入讲座的用户)。

标签: ruby-on-rails database-design rails-activerecord has-many-through


【解决方案1】:

看起来您的 _join.html.erb 使用 build 来形成一个新的 lecturerelationships 关联,然后 join! 调用使用 create 在同一对象上创建另一个。我的猜测是第二个调用中断了由第一个调用启动的事务,这就是您收到 database is locked: commit transaction 错误的原因。

我认为将此类代码排除在您的视野之外是一种很好的做法。

【讨论】:

  • 感谢 jordan - 我修复了 cdrosiers 指出的一些问题,现在我收到了一个新错误,它取代了旧的错误消息。有任何想法吗?谢谢!
  • 我所说的并不完全正确。您可以.build 一个关系然后.create! 另一个关系,第二个将创建成功。我认为您的代码正在构建一个具有某些属性的代码,然后创建一个具有相同属性的代码(可能是joinedlecture_id?),这导致 SQLite 抛出一个约束异常。不过,我不确定为什么,因为我认为 build 不会命中数据库。
  • (发表在错误的评论上)...正确的约旦,我正在尝试创建一个有很多“actives_id”(用户谁参加了讲座)。
  • 无论如何,很明显,由于某种约束,正在保存的任何内容都被数据库拒绝。输入一些调试输出或使用debugger 在保存之前查看讲师关系包含的内容。
【解决方案2】:

我将从以下模型开始,对成员资格表使用 Enrollment。
类命名对此至关重要。

class User < ActiveRecord::Base
  has_many :enrollments
  has_many :users, :through => :enrollments
end

class Lecture < ActiveRecord::Base
  has_many enrollments
  has_many users, :through => :enrollments
end

class Enrollment < ActiveRecord::Base
  belongs_to :user
  belongs_to :lecture
end

rails 的主要技巧是使用正确的名称并遵循约定,让框架为您完成大部分工作。离开这条路,错误可能无穷无尽,代码很快就会变得混乱:)

【讨论】:

  • 谢谢迈克尔-但这不是我目前所拥有的吗?只有我称之为“Lecturerelationships”而不是“Enrollment”
  • 我尝试设置“Lecturerelationship.rb”文件中的“Actives”和“JoinedLectures”的原因是因为我需要在讲座中对它们做很多事情,因此我试图将它们与普通的“用户”区分开来。我知道我还有很多东西要学。
  • 从这些关系和名称开始。是的,名称很重要,正如上面提到的 cdesrosiers 一样。相信我们,我们从艰苦的经验中学到了东西。一旦你可以使用这些关系,就做其他部分。 source 和 foreign_key 之类的小东西可能会导致错误或给出奇怪的错误消息。例如,您的路线看起来就像通过与那里的大量代码的关系来实现的。强烈建议您寻找与您的需求接近的 railscast。它们确实展示了最少的代码和最佳实践方式。
  • 我会通过范围而不是修改关系来做限定符。
  • 哦,当然是 Rails 聊天室 - stackoverflow.com/questions/790905/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-14
  • 2017-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多