I know how to pass parameters the dumb way. For example,
<%= link_to "Order", new_order_item_path(:item_id => #item.id) %>
The OrderItemsController receives it as params[:item_id] = id.
Problem:
#order_item = OrderItem.new(params)
raises an exception (Can't mass-assign protected attributes: action, controller). I can get around this with the following code.
#order_item = OrderItem.new
#order_item.item_id = params[:item_id]
I know the controller requires params[:order_item][:item_id] for new to work the first way. My question is, how do I get new_order_item_path to generate url? I know this isn't a major problem, but it just bugs me that I don't know the cleaner/proper way to do this. I have tried searching, but only received unrelated questions/answers/results.
Thanks
You didn't really specify if you didn't want to use it or not, but in your model, you could make the attribute item_id accessible like so:
class OrderItem < ActiveRecord::Base
attr_accessible :item_id
...
In this way,
#order_item = OrderItem.new(params)
would work.
Hope this helps.
How about this:
# Controller
def get_item_edit_method
#order = OrderItem.find("your criteria")
##order = OrderItem.new # if new
#item = Item.new()
end
def post_item_edit_method
#order = OrderItem.new(params) # should work now
#order.save
end
# End controller
<!-- view -->
<% #order.item = #item %>
<%= link_to "Order", new_order_item_path(#order) %>
<!-- end view -->
Related
I have a scope on my user model
I want to use this scope within a block on a view to display an option
my scope looks like this
scope :can_own_project, where('superuser = ? OR projectadmin = ?', true, true)
in my view I can achieve what I am looking to do by:
#stdprojectusers.each do |projectuser| %>
<% if (projectuser.superuser == true) || (projectuser.projectadmin == true) %>OPTION<%end%>`
what I would like to do is something like
<% if projectuser.can_own_project %> OPTION <% end %>
or
<% if projectuser == User.can_own_project %> OPTION <% end %>
any advise?
thanks
I don't think you want a scope. Scope's are applied to classes. If I'm reading you right, you are working with an instance. Is there a reason you can't simply define a method on that class?
class ProjectUser << ActiveRecord::Base
def can_own_project?
superuser == true || projectadmin == true
end
end
Note, I changed your method and appended a '?'. It's a habit of mine and isn't necessary, but I like the question form myself.
Your scope should work, but performance will (over time) take a major hit. What you'd want to do is:
<% if User.can_own_project.include?(projectuser) %> OPTION <% end %>
What I think you're looking for is a helper method...
module UserHelper
def does_user_own_project?(user)
user.superuser || user.projectadmin
end
end
Your view could then look like:
#stdprojectusers.each do |projectuser| %>
<% if does_user_own_project?(projectuser) %>OPTION<%end%>
If you'll want to use this outside the scope of this view, you could also make it an instance method on User:
class User < ActiveRecord::Base
def does_user_own_project?
self.superuser || self.projectadmin
end
end
I'm new to Rails, so it's possible I'm overlooking something simple. I have a Rails model called a story. Each story has_many segments, and each segment belongs_to a story. I use the same form to create both the story and its first segment by using a fields_for section of the form and setting the story model to accepts_nested_attributes_for :segments. I am currently able to use the form to create both a story and a segment simultaneously.
The problem is that each story also needs to store the id of its first segment, but when I'm saving the story, the segment hasn't yet been saved, so it doesn't yet have an id to store in the story, and I haven't been able to find a handle for the segment after the form is submitted so that I can save the segment first before the story is created. So my question is how do I save a record of the first_segment_id inside the story?
The following code may be relevant:
in app/models/story.rb
class Story < ActiveRecord::Base
attr_accessible :segments_attributes
has_many :segments
accepts_nested_attributes_for :segments
end
in app/models/segment.rb
class Segment < ActiveRecord::Base
attr_accessible :words
belongs_to :story
end
in app/views/stories/_ form.html.erb
<%= form_for(#story) do |f| %>
#...stories fields...
<%= f.fields_for :segments do |segment_form| %>
<div class="field">
<%= segment_form.label :words %><br />
<%= segment_form.text_area :words %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
in app/controllers/stories_ controller.rb
def new
#story = Story.new
#segment = #story.segments.build
# If I try replacing the above with #segment = #story.segments.create
# then I get the error message "You cannot call create unless the
# parent is saved," which is problematic because I need to find some way
# to get the id of #segment to save in the parent story, but the segment
# won't have an id until after it has been saved.
respond_to do |format|
format.html # new.html.erb
format.json { render json: #story }
end
end
def create
#story = Story.new(params[:story])
# #segment.save
# #story.first_segment_id = #segment.id
# If I uncomment the above two lines, I get the error message
# "undefined method `save' for nil:NilClass". It appears that
# #segment hasn't been passed from the "new" method above to
# this method as a handle of the first segment created, so I'm not
# able to save it to get an id for it before saving the story.
# Is there some way to save the segment here?
respond_to do |format|
#...if #story.save...
end
end
The params hash submitted by the form looks something like:
{ "story"=>{ Various_other_story_fields,
"segments_attributes"=>{"0"=>{"words"=>"dfsdsa"}}},
"commit"=>"Create Story"}
Is there a way to save the first segment's id in the story? I think perhaps I need to add a before_create inside my story model instead, but I'm not sure how do to this.
I would approach this differently, adding a numeric sort_order column to Segment so that you're not relying on Segment ids to determine what order they go in. Then you can define something like the following on your Story model rather than explicitly referencing the first segment in the database:
def first_segment
segments.order(:sort_order).first
end
If you're certain you need to store the first segment ID in the story, you can .save the story so that it knows its ID, saves its children, and knows their IDs. Something like:
def create
#story = Story.new(params[:story])
#story.save # Save the story and its child segment so that they both have IDs
#story.first_segment_id = #story.segments.first.id
#story.save
...
end
You should be able to do something like:
class Story < ActiveRecord::Base
attr_accessible :segments_attributes
has_many :segments
has_one :first_segment
accepts_nested_attributes_for :segments
end
def new
#story = Story.new
#segment = #story.segments.build
#story.first_segment = #segment
...
You'll have to add story_id to your segment table.
I am trying to create a nested attribute form to create a model which is primarily an association "connector" between two other models. In my case, the models represent books, awards, and the "connector" model book_awards. When I am editing a book, I want to be able to quickly select which awards it has won.
I've been using
http://railscasts.com/episodes/196-nested-model-form-part-1
to help me get started, but I'm afraid I'm pretty much stuck.
Another SO question which seems similar is
accepts_nested_attributes_for with find_or_create? Unfortunately, it's also not quite what I'm doing and I haven't been able to adapt it.
My models look like this. Each model has additional attributes and validations etc, but I've removed them for clarity.
class Book < ActiveRecord::Base
has_many :book_awards
accepts_nested_attributes_for :book_awards, :allow_destroy => true
end
class Award < ActiveRecord::Base
has_many :book_awards
end
class BookAward < ActiveRecord::Base
belongs_to :book, :award
end
In my book controller methods for edit and new, and the failure cases for create and update I have a line #awards = Award.all.
In my view, I would like to see a list of all awards with check boxes next to them. When I submit, I would like to either update, create, or destroy a book_award model. If the check box is selected, I would like to update an existing model or create a new one if it doesn't exist. If the check box isn't selected, then I would like to destroy an existing model or do nothing if the award never existed. I have a partial for book_awards. I'm not sure if the check box selector should be in this partial or not.
I think my check box will be my hook to :_destroy but with its polarity reversed. I think something like this will basically do it:
= f.check_box :_destroy, {}, 0, 1
Currently, I have this in my partial but I'm not sure where it really belongs.
Next comes my view which currently doesn't work, but maybe it will help demonstrate what I'm trying to do. I loop through the awards and use a fields_for to set nested attributes for anything that already exists. It's horribly ugly, but I think it somewhat works. However, I don't really know how to get started with the else case.
= f.label :awards
- #awards.each do |a|
- if f.object.awards && f.object.awards.include?(a)
= f.fields_for :book_awards, f.object.book_award.select{|bas| bas.award == a } do |ba|
= render 'book_awards', :f => ba, :a => a
- else
= fields_for :book_awards do |ba|
= render 'book_awards', :f => ba, :a => a
I would prefer the awards to be listed in the same order each time (my #awards assignment in the controller will probably specify the order) as opposed to listing the existing awards first or last.
I hate to answer my own question, but I finally figured out something which works. The first thing I needed to do was to update the "new" case based on the crazy object which was included in the railscast. Next, I needed to manually set the :child_index. Finally, I needed to manually set the :_destroy check box appropriately.
.field
= f.label :awards
- #awards.each_with_index do |a,i|
- if exists = (f.object.awards && f.object.awards.include?(a))
- new_ba = f.object.book_awards.select{|s| s.award == a}
- else
- new_ba = f.object.class.reflect_on_association(:book_awards).klass.new
= f.fields_for :book_awards, new_ba, :child_index => i do |ba|
= render 'book_awards', :f => ba, :a => a, :existing => exists
My partial looks like this:
.field
= f.check_box :_destroy, {:checked => existing}, 0, 1
= f.label a.name
= f.hidden_field :award_id, :value => a.id
= f.label :year
= f.number_field :year
It's not horribly pretty, but it seems to do exactly what I wanted.
I have in my controller this:
#itemsok = Search.where("first_item_id = ?", params["3"])
This is sopposed to be a query in the search table of the database asking for all the searches that have a first_item_id = 3 ...
Question 1 .- The syntax is I found it in http://guides.rubyonrails.org/active_record_querying.html but im not sure if im using it right?
Ok the question 2 is, I have this on the controller, is it ok to have querys in the controller?
In the view im printing the variable <%= #itemsok %> and all I get is a
ActiveRecord::Relation:0x007fd3d3e894d8
Any suggestions?
Thanks in advance.
ActiveRecord 3 lets you chain relations together so you can do something like this:
#itemsok = Search.where("first_item_id = ?", params["3"]).where("foo = ?", "bar")
The where() function returns an ActiveRecord::Relation. Generally this isn't a problem, since if you use the object it'll automatically run the query and return the results on the object so you'll get the database objects. AR doesn't run the query until it's actually needed.
Where will return a list of items (Array), so if you're just debugging, change your view to this:
<%= debug #itemsok.to_a %>
You seem to be constructing the query wrong way.
If you want to search for records with first_item_id = 3, you should do:
Search.where("first_item_id = ?", 3)
This will return an array of matching records, something you can't easily print with <%= #itemsok %>. You should iterate over the elements and print each one:
<% #itemsok.each do |item| %>
<%= item.name %>
<% end %>
I'd also suggest defining to_s method for the objects you want to print.
class Search
def to_s
name
end
end
Then you can simply print the object and to_s method will be automatically called for you:
<% #itemsok.each do |item| %>
<%= item %>
<% end %>
The right way to do is to define a namedscope in the model and then use it in the controller.
Something similar to this :
class Search < ActiveRecord::Base
named_scope:item_ok,lambda {|*args|{:conditions=>["item_id >= ?", args.first]}}
end
and then call the namedscope from the controller like this :
#itemsok = Search.item_ok(params[:value])
I am working the acts-as-taggable-on gem and have a question about how to filter down search results based on tags users select. Here's an abridged look at my controller:
class PhotosController < ApplicationController
def index
#photos = Photo.where(["created_at > ? AND is_approved = ?", 1.months.ago, true])
#tags = ["Animals", "Architecture", "Cars", "Flowers", "Food/Drink", "General", "Landscape", "Mountains", "Nature"]
end
def search_by_tag(tag)
#photos = Photo.where('tagged_with LIKE ?', tag)
end
end
Photos/index
<% #tags.each do |tag| %>
<%= link_to tag, {:search_by_tag => tag}, :class => "tag" %>
<% end %>
This lists out all of the tags from the hash #tags defined in index, but clicking them doesn't actually filter anything down. Here's a look at what clicking one of those links produces in the log:
Started GET "/photos?search_by_tag=Animals" for 127.0.0.1 at Sun Oct 09 17:11:09 -0400 2011
Processing by PhotosController#index as HTML
Parameters: {"search_by_tag"=>"Animals"}
SQL (0.5ms) SELECT name FROM sqlite_master WHERE type = 'table' AND NOT name = 'sqlite_sequence'
The result I want is for the page to display only Photos that are tagged_with whichever tag was clicked on. I can't quite figure out how to accomplish this.
(Side-question: I can't seem to find a way to list out all of the tags from the tags table that acts-as-taggable-on generated. Doing something like Photo.tagged_with or Photo.tags doesn't work. I am able to see the "tags" table the gem created, and the entries inside of it; I'm just not really clear how to handle that using this gem)
Any thoughts greatly appreciated.
UPDATE
I've updated my code and am a bit closer.
class PhotosController < ApplicationController
def search_by_tag
#photos = Photo.tagged_with(params[:tag_name])
end
photos/index
<% Photo.tag_counts_on(:tags).map(&:name).each do |tag| %>
<%= link_to tag, {:action => 'search_by_tag', :tag_name => tag}, :class => "tag" %>
<% end %>
I believe this is closer, but still working through this...
You have a number of errors in your code:
Your link_to call is actually calling the index action.
Your search_by_tag method is expecting an argument, where it should be using the params hash to access the parameters passed to it in the web request.
tagged_with is a class method added by acts_as_taggable_on, not a field in your table - therefore you can't use it in the where method like you have done.
Finally, to get all the tag names: Photo.tag_counts_on(:tags_or_whatever_you_tagged_on).map(&:name)
Take a look at the acts_as_taggable_on documentation and you'll see examples of how to use tag_counts_on and tagged_with.
As for the Rails things: http://guides.rubyonrails.org/ http://railsforzombies.org/ and/or http://railscasts.com/