I have 3 objects: users, travels, points.
A user has many travels, a travel has many points, a point belongs to one travel e one user.
A travel has also a boolean attribute (:open) which tells if is it in curse or not.
The problem is that I can't save "travel_id" of the current travel in my points table.
Here is the code:
class Point < ActiveRecord::Base
belongs_to :travel, :foreign_key=> "travel_id"
belongs_to :user, :foreign_key=> "user_id"
end
class Travel < ActiveRecord::Base
has_one :user, :foreign_key => "user_id"
has_many :ways
has_many :points
attr_accessible :description, :start_date, :last_date
validates_date :last_date, :on_or_after => :start_date
end
Points controller:
...
def create
#point = Point.new(params[:point])
#point.user_id = current_user.id
#travel = current_user.travels.find(:all, :conditions => {:open => true})
#point.travel_id = #travel.id
respond_to do |format|
if #point.save
format.html { redirect_to(#point, :notice => 'Point was successfully created.') }
format.xml { render :xml => #point, :status => :created, :location => #point }
else
format.html { render :action => "new" }
format.xml { render :xml => #point.errors, :status => :unprocessable_entity }
end
end
end
...
Every time I try to save a new point, #point.travel_id = -614747648
A few things could do with being fixed up here.
Firstly, you don't need to specify :foreign_key when the key is just the same as the relation name + _id.
Second, you don't need to (and generally shouldn't) set the foo_id fields directly; it's more usual to do #point.user = current_user.
Thirdly, and the direct cause of your problem, is that #travel has been set to the result of a find(:all, ...) call - so it's an Array of Travel objects. What you're saving into #point.travel_id will be Ruby's internal id for the #travel Array, rather than a database ID for a single row.
Related
I'm trying to update a record which includes a has_many association and wish to process any errors. Using update_attributes works great if there are no associations but if an association is not valid (violates a unique constraint, for example) then all I get is a ActiveRecord::RecordNotSaved error, but nothing in the #object.errors.
Controller Code
respond_to do |format|
begin
if #calmapp_version.update_attributes(params[:calmapp_version])
tflash('update', :success, {:model=>##model, :count=>1})
format.html { redirect_to( :action => "index")}
format.xml { head :ok }
else
format.html { render :action => "edit" }
end
rescue ActiveRecord::RecordNotSaved => e
flash[:error] = #calmapp_version.errors.full_messages
format.html { render :action => "edit" }
end
end
Models
class CalmappVersion < ActiveRecord::Base
has_many :calmapp_versions_translation_languages, :dependent => :destroy
....
end
class CalmappVersionsTranslationLanguage < ActiveRecord::Base
belongs_to :calmapp_version
belongs_to :translation_language
validates :translation_language_id, :uniqueness => {:scope=> :calmapp_version_id}
end
Where is the violation of uniqueness message and how do I access it?
I would try using update_attributes!. Notice the !. This will produce an exception if a record isn't valid and give you more insight into what's going wrong.
In regards to the other question Where is the violation of uniqueness message and how do I access it?
you can look here (http://guides.rubyonrails.org/active_record_validations.html#uniqueness) and include the message in the uniqueness hash such as
validates :translation_language_id, :uniqueness => {:scope=> :calmapp_version_id, message => 'There Can Be Only 1'}
I am running into a strange situation, considering the following models:
class Collection < ActiveRecord::Base
attr_accessible :name, :season, :year
has_many :collection_items_assocs
has_many :items, :through => :collection_items_assocs
end
class Item < ActiveRecord::Base
attr_accessible :name, :reference, :item_type_id
has_many :pictures
has_one :item_type
end
class CollectionItemsAssoc < ActiveRecord::Base
attr_accessible :collection_id, :item_id
belongs_to :item
belongs_to :collection
end
I can successfully retrieve Items associated to a Collection with the following code:
# GET /collections/1
# GET /collections/1.json
def show
#collection = Collection.find(params[:id])
#collection.items = Collection.find(params[:id]).items
respond_to do |format|
format.json { render json: #collection.to_json(:include => {:items => #collection}) }
end
end
But when I try to include pagination (for items) like that
# GET /collections/1
# GET /collections/1.json
def show
#collection = Collection.find(params[:id])
**#collection.items = Collection.find(params[:id]).items.paginate(:page => params[:page],:per_page =>1)**
respond_to do |format|
format.json { render json: #collection.to_json(:include => {:items => #collection}) }
end
end
It works for the following call
/retailapp/collections/1?format=json&**page=1**
Then if I call
/retailapp/collections/1?format=json&**page=2**
the records in the association table CollectionItemsAssoc are deleted
I really don't get it
Thanks for your help
The problem is the code to fetch the items
#collection.items = Collection.find(params[:id]).items
it assigned the fetched items to current collection object.
you need to change the response to support the pagination on associate objects
def show
#collection = Collection.find(params[:id])
respond_to do |format|
format.json {
json_hash = #collection.as_json
json_hash[:items] = #collection.items.paginate(:page => params[:page],:per_page =>1).as_json
render json: json_hash.to_json
}
end
Additionally you can overwrite to_json method inside Collection model.
I have the following classes:
class VideoChannel < ActiveRecord::Base
#Associations
belongs_to :video_playlist, :dependent => :destroy
VideoChannel.video_playlist_name
delegate :name, :id, :list_type, :list_id, :manual, :to => :video_playlist, :prefix => true
#validations
validates_presence_of :name
#After Functions
def after_create
video_playlist = VideoPlaylist.new(:name => self.name,
:list_type => "VideoChannel",
:list_id => self.id)
video_playlist.save
end
And :
class VideoPlaylist < ActiveRecord::Base
belongs_to :list, :polymorphic => true
has_many :video_channels, :dependent => :destroy
delegate :name, :id, :description, :to => :video_channel, :prefix => true
end
I'm trying to use the Rails Delegate function to create a link in the VideoChannel page that allows me to to link to the Video Playlist and edit the contents there. So the association is there and You can currently edit the playlists by going through the playlists section but we want to combine them. I can't seem to figure this out. Im also very new to Rails, still working through the guides etc.
Edit: Here's the view code
<%= link_to '<span class="pen icon"></span>Edit',
content_url(:controller =>"video_playlists", :id => channel.video_playlist_id, :action => "edit"),
:class => "button right" %>
Here are teh relevant pieces of the controllers:
class VideoChannelsController < ApplicationController
# GET /videochannels
# GET /videochannels.xml
def index
#video_channels = VideoChannel.roots(:order => 'order_num')
#video_channels_parents = #video_channels.group_by {:parent_id}
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #video_channels }
end
end
# GET /videochannels/1
# GET /videochannels/1.xml
def show
#video_channel = VideoChannel.find(params[:id], :order => 'order_num')
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #video_channel }
end
end
end
class VideoPlaylistsController < ApplicationController
# GET /video_playlists
# GET /video_playlists.xml
def index
if !params[:with].nil?
#video_playlists = VideoPlaylist.find(:all, :conditions => {:list_type => 'VideoShow'})
else
#video_playlists = VideoPlaylist.find(:all, :conditions => {:list_type => 'Section'})
end
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #video_playlists }
end
end
# GET /video_playlists/1
# GET /video_playlists/1.xml
def show
#video_playlist = VideoPlaylist.find(params[:id], :include => [{:video_video_playlists => :video}, {:videos => :asset}, {:videos => :content_image}])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #video_playlist }
end
end
end
Where did the line
VideoChannel.video_playlist_name
Come from? What's it doing? You're also calling a method on the class not an instance (sort of - Ruby isn't quite like this, but it's enough to explain).
Anyway:
Delegate is really for avoiding lots of train wreck code like this:
fred.jim.bill.xxx
You've said that they belong to each other - the relationships look like they're the wrong way round. Why are you creating the parent from inside the child? How are you going to have many video channels belonging to a given playlist?
I think you need to look at build and the relationship names. To gat past me maybe misunderstanding your model, lets have switch to a product that has many stock items:
class Product < ActiveRecord::Base
has_many :stock_items
end
class StockItem < ActiveRecord::Base
belongs_to :product
end
This means that stock_item will have a column product_id.
So, say you're creating a product you'd do something like:
product.stock_items.build # :whatever the params are required
This automatically sets the id's for you and means you don't have to set id's. Then when you do product.save it will save all the related stock items too.
And in the view for this toy model, then if you were displaying one of the stock items, you'd use delegate to show the name of the product in the view without having to do lost of stock_item.product.name (for example).
I hope this helps.
I'm trying to get a nested form view to update properly. This is however causing problems when the second form has existing data.
I'm using accepts_nested_attributes_for and nested_form_for. The second which only purpose is to dynamically add the form element using js. See github for more
The error I'm getting is:
Couldn't find Muscle with ID=3685340 for Exercise with ID=212831413
I've tried to manually do the updating but my code didnt really work and I'm under the impression that it shouldnt be needed since rails is suppose to take care of it under the hood.
The idea is that: Exercises has many Muscles through Targets
And from within the Exercise form I want to be able to add target muscles.
My models:
class Exercise < ActiveRecord::Base
has_many :targets, :dependent => :destroy
has_many :muscles, :through => :targets
accepts_nested_attributes_for :muscles, :reject_if => :all_blank
...
end
class Target < ActiveRecord::Base
belongs_to :exercise
accepts_nested_attributes_for :exercise, :update_only => true
belongs_to :muscle
end
class Muscle < ActiveRecord::Base
has_many :targets, :dependent => :destroy
has_many :exercises, :through => :targets
end
My (haml) view:
%p
%b Target(s):
= f.fields_for :muscles do |e|
= e.collection_select :id, Muscle.all, :id, :name
= e.link_to_remove "-remove"
= f.link_to_add "Add target muscle", :muscles
And finally my failing controller:
def update
#exercise = Exercise.find(params[:id])
#exercise.user = current_user
params[:exercise][:muscles_attributes].each { |id, muscle|
target = Target.where(:exercise_id => #exercise.id , :muscle_id => muscle[:id]).first
if target && !(muscle[:_destroy] == "false")
puts "!!>>>>>>>>>>>>>>>>>>destroy target #{target.exercise_id} #{target.muscle_id}"
target.destroy
else
if !target
t = #exercise.targets.build(:muscle_id => muscle[:id])
t.save
end
end
}
respond_to do |format|
if #exercise.update_attributes(params[:exercise])
format.html { redirect_to(#exercise, :notice => 'Exercise was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #exercise.errors, :status => :unprocessable_entity }
end
end
end
Please let me know if I should expose more of my code (the final result will be opensource anyway) ill happily push to github or whatever is requested, thanks in advance.
You could achieve this by manipulating the intermediate table, here targets.
Insert in your model:
accepts_nested_attributes_for :targets
And in your html, append this line with javascript:
<input name="exercise[targets_attributes][0][muscle_id]" value="the_muscle_id_goes_here" type="hidden">
I am having that problem that my model dont want to save. I have a token field input for tags.
I have followed this guide for the token input: http://railscasts.com/episodes/258-token-fields
I get this error when I try to create a new konkurrancer:
NoMethodError in Admin/konkurrancersController#create
undefined method `class_name' for nil:NilClass
Rails.root: C:/Rails/konkurranceportalen
Application Trace | Framework Trace | Full Trace
app/models/konkurrancer.rb:15:in `tag_tokens='
app/controllers/admin/konkurrancers_controller.rb:48:in `new'
app/controllers/admin/konkurrancers_controller.rb:48:in `create'
http://pastie.org/1834194
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"yo7wcAQl81tx3zZpPP44ENPYzYRZLpgyYKY+HK3yFKM=",
"konkurrancer"=>{"name"=>"Vind en rejse",
"banner2"=>"asdasd",
"tracking"=>"sadasd",
"vaerdi"=>"12222",
"tid"=>"1 min",
"tag_tokens"=>"1",
"bedom"=>"2",
"kategori_id"=>"9",
"form"=>"Nyhedsbrev",
"partner"=>"Iqmedier",
"udtraekkes(3i)"=>"30",
"udtraekkes(2i)"=>"4",
"udtraekkes(1i)"=>"2011",
"udtraekkes(4i)"=>"08",
"udtraekkes(5i)"=>"26",
"arrangeor"=>"",
"note"=>""},
"commit"=>"Opret konkurrence"}
My konkurrancer model:
class Konkurrancer < ActiveRecord::Base
attr_accessible :name, :tag_tokens
has_many :tagsmenus
has_many :tags, :through => :tagsmenus
attr_reader :tag_tokens
def tag_tokens=(ids)
self.tag_ids = ids.split(",")
end
end
My tag model:
class Tag < ActiveRecord::Base
has_many :tagsmenus
has_many :konkurrancers, :through => :tagsmenus
has_friendly_id :name, :use_slug => true
before_save :assign_cached_slug, :unless => :cached_slug?
protected
def assign_cached_slug
self.cached_slug = self.name.gsub(/\s+/, '_').gsub(/[^\w\-]/, '')
end
end
My tagmenu model:
class Tagsmenu < ActiveRecord::Base
end
My controller:
def new
#konkurrancer = Konkurrancer.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #konkurrancer }
end
end
# POST /konkurrancers
# POST /konkurrancers.xml
def create
#konkurrancer = Konkurrancer.new(params[:konkurrancer])
respond_to do |format|
if #konkurrancer.save
format.html { redirect_to(:admin_konkurrancers, :notice => 'Konkurrancer was successfully created.') }
format.xml { render :xml => :admin_konkurrancers, :status => :created, :location => #konkurrancer }
else
format.html { render :action => "new" }
format.xml { render :xml => #konkurrancer.errors, :status => :unprocessable_entity }
end
end
end
I have created the join table and the model and also added the relation to my tag model.
Your model has some conflicting statements. You first define:
attr_accessor ... :tag_tokens
then later have:
attr_reader :tag_tokens
which is not necessary given the first line or vice versa given that later you have a deinition for the setter:
def tag_tokens(ids)
self.tag_ids = ids.split(',')
end
I don't see tag_ids defined either given it is not a column in your table. You should probably remove the attr_accessor definition for the tag_tokens and then define the tag_ids method for starters.
class Tagsmenu < ActiveRecord::Base
belongs_to :konkurrancer
belongs_to :tag
end