2012-02-28 51 views
3

當我提交表單來更新我的模型我得到在瀏覽器這個錯誤:Rails - 活動記錄「RuntimeError:不能修改凍結字符串」以某種方式與表單生成器相關?

ActiveRecord::StatementInvalid in CoachesController#update 

RuntimeError: can't modify frozen String: INSERT INTO "availabilities" ("coach_id", "created_at", "day", "hour", "updated_at") VALUES (?, ?, ?, ?, ?) 

軌道控制檯這樣說:

(0.0ms) begin transaction 
Binary data inserted for `string` type on column `day` 
SQL (0.5ms) INSERT INTO "availabilities" ("coach_id", "created_at", "day", "hour", "updated_at") VALUES (?, ?, ?, ?, ?) [["coach_id", 14], ["created_at", Mon, 27 Feb 2012 21:59:05 UTC +00:00], ["day", "Monday"], ["hour", 20], ["updated_at", Mon, 27 Feb 2012 21:59:05 UTC +00:00]] 
RuntimeError: can't modify frozen String: INSERT INTO "availabilities" ("coach_id", "created_at", "day", "hour", "updated_at") VALUES (?, ?, ?, ?, ?) 
(0.1ms) rollback transaction 
Completed 500 Internal Server Error in 25ms 

ActiveRecord::StatementInvalid (RuntimeError: can't modify frozen String: INSERT INTO "availabilities" ("coach_id", "created_at", "day", "hour", "updated_at") VALUES (?, ?, ?, ?, ?)): 
app/models/coach.rb:93:in `block (2 levels) in update_general_availability' 
app/models/coach.rb:92:in `each' 
app/models/coach.rb:92:in `block in update_general_availability' 
app/models/coach.rb:91:in `each' 
app/models/coach.rb:91:in `update_general_availability' 
app/controllers/coaches_controller.rb:25:in `update' 

多次實驗後,我發現如何解決這個錯誤,但不是爲什麼我首先得到它。

我有兩個模型:CoachAvailabilities,與has_manybelongs_to關聯。這是可用性表的模式:

# Table name: availabilities 
# id   :integer   not null, primary key 
# coach_id :integer 
# day  :string(255) 
# hour  :integer 

它存儲在白天,一個教練是免費的一週小時的一天。

我在Coach模型中寫了兩種方法來更容易地處理教練的每週可用性。他們使用嵌套的哈希表,因此您可以查詢教練在給定時間是否空閒。 (例如:general_availability["Thursday"]["12"] #=> true

#coach.rb 
class Coach < ActiveRecord::Base 
    ... 

    # Creates a hash table mapping day and hour to true if available then, false otherwise 
    # Form is general_availability["day"]["hr"]. Per Availability model, "0" = midnight, and 
    # day of the week is of the form "Monday" or "Tuesday". 
    def general_availability 
    h = Hash.new() 
    %w(Monday Tuesday Wednesday Thursday Friday Saturday Sunday).each { |day| h[day] = Hash.new(false) } 

    self.availabilities.each do |a| 
     h[a.day][a.hour.to_s] = true 
    end 

    return h 
    end 

    # Takes a hash table of the kind returned by general_availability and updates 
    # this coach's records in the Availabilities table 
    def update_general_availability(ga_hash_table) 
    self.availabilities.clear 

    ga_hash_table.each do |day, hrs| 
     hrs.each do |hr, val| 
     self.availabilities.create({day: day, hour: hr.to_i}) 
     end 
    end 
    end 

這是部分顯示教練的每週可用性作爲表。每天/每小時單元格是一個複選框,教練可以選中或取消選中以指示它們是否免費。

<!-- availabilities/_scheduler.html.erb --> 
<h2>General Availability</h2> 
Please check the times below that you would generally be available for a training session. 
<table class="table" id="availabilities_table"> 
    <tr> 
    <th>Time</th> 
    <% days_of_the_week.each do |day| %> 
     <th><%= day %></th> 
    <% end %> 
    </tr> 
    <% (6..21).each do |hr| %> 
    <tr> 
     <td><%= format_as_time hr %></td> 
     <% days_of_the_week.each do |day| %> 
     <% is_checked = @general_availability[day][hr.to_s] %> 
     <td class="availabilities_cell"> 
      <%= check_box_tag "availability[#{day}][#{hr}]", true, is_checked, :class => 'availabilities_check_box' %> 
     </td> 
     <% end %> 
    </tr> 
    <% end %> 
</table> 

這是控制器:

# coaches_controller.rb 
... 
def edit 
    @coach = current_user.coach 
    @general_availability = @coach.general_availability 
end 

def update 
    @coach = Coach.find(params[:id]) 

    @coach.update_attributes(params[:coach]) 
    if @coach.save 
    @coach.update_general_availability(params[:availability]) 
    redirect_to @coach 
    end 
    # ... 
end 

它是線

@coach.update_general_availability(params[:availability]) 

導致錯誤。

現在,這是我的問題。 爲什麼這個視圖會導致上述錯誤?

<!-- edit.html.erb version 1 --> 
<h1><%= @coach.user.first_name %> </h1> 
<%= form_for @coach, :html => { :multipart => true } do |f| %> 

    <%= f.label :profile_photo %> 
    <%= f.file_field :profile_photo %> 

    <div class="field"> 
    <%= f.label :phone_number %> 
    <%= f.text_field :phone_number %> 
    </div> 

    ... More Form Fields Here ... 

    <%= render 'availabilities/scheduler' %> 
    <%= f.button %> 

<% end %> 

雖然這種觀點不?

<!-- edit.html.erb version 2 --> 
<h1><%= @coach.user.first_name %> </h1> 
<%= form_for @coach, :html => { :multipart => true } do |f| %> 

    <%= f.label :profile_photo %> 
    <%= f.file_field :profile_photo %> 

    <div class="field"> 
    <%= f.label :phone_number %> 
    <%= f.text_field :phone_number %> 
    </div> 

    ... More Form Fields Here ... 

    <%= f.button %> 

<% end %> 

<%= form_for @coach, :class => "form-vertical" do |f| %> 
    <%= render 'availabilities/scheduler' %> 
    <%= submit_tag "Update Schedule" %> 
<% end %> 

注意,在前者部分是表單生成器形式的內部,而在第二種情況下的部分呈現爲低於其自己form_for

,在我從我上面粘貼日誌飛出的部分是此行:

Binary data inserted for `string` type on column `day` 

不出現時的形式作品(例如,在表格的版本2)。這似乎很重要,但我不知道它是什麼意思或爲什麼發生。

非常感謝!

回答

2

想通了。 Ruby哈希表鍵被凍結。所以我的PARAMS樣子:

params[:availability][:Thursday][:10] = "true" 

當我update_general_availability方法做:

self.availabilities.create({day: day, hour: hr.to_i}) 

:day"Thursday",但SQLite的適配器的理解是有Encoding::ASCII_8BIT(又名 「二進制」),並嘗試做encode! 'utf-8'它。但是,由於它被凍結,所以引發了運行時凍結字符串錯誤。問題解決了通過添加這些行到update_general_availability方法:

day = day.dup 
hr = hr.dup 

現在,因爲他們是重複的,而不是哈希鍵本身,他們可以得到編碼成UTF-8。

相關問題