论坛首页 编程语言技术论坛

同一个表单提交一对多关联的多个Model

浏览 5973 次
精华帖 (0) :: 良好帖 (7) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-07-06  
最近做了一个小项目.在项目中有一个提交产品,产品有一个信息介绍..产品与介绍是一对多的关系..在添加产品的时候要进行同一表单提交多个Model..查看了一些资料,实现的方法如下.
首先来看看数据库和Model的
数据库脚本迁移文件
class CreateProductInfos < ActiveRecord::Migration
  def self.up
    create_table :product_infos do |t|
      t.string :title,:limit=>100,:null=>false
      t.string :content,:null=>false
      #对应的产品
      t.integer :product_id 
      t.timestamps
    end
  end

  def self.down
    drop_table :product_infos
  end
end

class CreateProducts < ActiveRecord::Migration
  def self.up
    create_table :products do |t|
      t.string :name, :limit => 100, :null => false
      t.text :remark, :null => true
      t.string :img_path
      t.timestamps
    end
  end
  def self.down
    drop_table :products
  end
end

在Model部分..添加上关联.
class ProductInfo < ActiveRecord::Base
  belongs_to :product
end
class Product < ActiveRecord::Base
  has_many :product_infos
end



View设计,View部分主要部分注意,
<%= link_to_remote "添加产品信息" , :update => "product_types",:url => { :action => "add_product_type" },:position => 'bottom'  %>

使用Ajax方式请求服务器.返回的数据更新倒product_types元素上..这个元素就是一个td..代码在最下边贴吧..
controller很简单,就是返回一个模板,主要的目的是动态的添加信息
  def add_product_type
    render :partial => "product_type"
  end

product_type很简单,就是两个产品信息的文本框
<p>
	<%=text_field_tag "product_infos[][title]","",:size=>20%>
	<%=text_field_tag "product_infos[][content]","",:size=>40%>
</p>

写到这里就实现了一个动态添加一个商品信息的页面..当用户点击"添加产品信息"按钮的时候,就会在页面上增加两个文本框,点一次多一个,点一次多一个!!很简单吧~~嘿嘿
然后就是controller上save方法了..我们在页面上添加了一个product_infos[],那么controller上通过params[:product_infos]取出商品信息,然后添加倒商品上.保存到数据库就OK啦.
Controller的设计
def save
    #获取所有商品的类型.
    @product_types = ProductType.find :all
    if request.post? 
      #使用表单数据创建一个商品对象
      @product = Product.new params[:product]
      #迭代页面传递来的所有产品信息
      params[:product_infos].each do |info|
      #根据信息创建一个信息实体
        product_info = ProductInfo.new info
        #如果产品信息的标题存在,
        if product_info.title.size > 0
          将产品信息和产品关联上
          @product.product_infos << product_info
        end
      end
      #保存产品
      if @product.save
        #如果存在图片,那么上传图片,更新商品信息
        img_path = add_file @product.img if @product.img.size > 0
        if img_path
          @product.update_attributes(:img_path => "/uploads/"+img_path)
        end
        goto_index "保存成功"
      end
    end
  end

这个是完整的View页面...
<%form_tag ({:action=>:save},:multipart =>true) do%>
	<table width="100%">
		<tr>
			<td width="50px">产品名:</td>
			<td>
				<%=collection_select "product","product_type_id",@product_types,"id","name"%>
			</td>
		</tr>
		<tr>
			<td>标题:</td>
			<td><%=text_field "product","name"%></td>
		</tr>
		<tr>
			<td colspan="2">
				<%=file_field "product","img"%>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<%= fckeditor_textarea("product", "remark", { :toolbarKit => 'Simple', :width => '95%', :height => '350px' }) %>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<table width="100%">
					<tr>
						<td width="150px">信息标题</td>
						<td>信息内容</td>
					</tr>
					<tr>
						<td colspan="2" id="product_types">
							<%render :partial => "product_type"%>
						</td>
					</tr>
				</table>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<%= link_to_remote "添加产品信息" , :update => "product_types",:url => { :action => "add_product_type" },:position => 'bottom'  %>
			</td>
		</tr>
		<tr>
			<td colspan="2">
				<%= submit_tag "保存" %>
			</td>
		</tr>
	</table>
<%end%>

修改view和save.rhtml是一样的..只不过多了一个循环,先把数据库中已有的信息显示出来.
<%for info in @product.product_infos%>
	<p>
		<%=text_field_tag "product_infos[][title]",info.title,:size=>20%>
		<%=text_field_tag "product_infos[][content]",info.content,:size=>40%>
	</p>
<%end%>

更新部分的Collector和save的稍有不同.我使用update_attributes更新数据库,那么就要把infos添加到params[:product]中.应该实现params[:product][:product_infos] = Array.new
在Array.new中是一个一个的ProductInfo.new
代码如下
  def update
    @product_types = ProductType.find :all
    @product = Product.find params[:id]
    if request.post?
      #创建一个新的元素
      params[:product][:product_infos] = Array.new
      #迭代页面提交上来infos
      params[:product_infos].each do |info|
        #创建ProductInfo实体
        product_info = ProductInfo.new info
        #如果ProductInfo实体的标题有效
        if product_info.title.size > 0
          #将ProductInfo添加到hash中
          params[:product][:product_infos] << product_info
        end
      end
      #根据hash更新商品
      if @product.update_attributes params[:product]
        img_path = add_file @product.img if @product.img.size > 0
        if img_path
          @product.update_attributes(:img_path => "/uploads/"+img_path)
        end
        goto_index "修改成功"
      end
    end
  end
   发表时间:2008-07-06  
在上传图片部分对sql执行了两次,先添加,后更新.感觉不太好..但是对上传不太了解..好像只有在执行了save或者update以后才会生成这个img对象.有没有更好的上传解决方案呢?
0 请登录后投票
   发表时间:2008-07-09  
我觉得你把增加一行产品的信息收集表单,用javascript来实现更方便一点。
0 请登录后投票
   发表时间:2008-07-09  
以前也有一个项目是用js实现的(java项目),但是在后期发现,因为很多js代码的存在,页面后期很难维护.
而且从性能上来将,一个静态页面请求并不会给服务器多大负担,我感觉还是这种ajax方式来处理方便.
0 请登录后投票
   发表时间:2008-07-10  
看看这个http://railscasts.com/episodes/75
0 请登录后投票
   发表时间:2008-07-11  
严重同意studyworks。我看到这篇的标题马上就想到了complex form的三个rais casts。从part 1看起会更容易理解一些。
0 请登录后投票
   发表时间:2008-07-11  
刚刚看了一下.确实不一样哦..嘿嘿!!看来水平还不够,继续努力!
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics