So I have this structure of application: a Game model which has many Allies and many Enemies.
I want to create a custom action for Game dedicated to create and submit enemies and allies.
So in the view I will have 2 fields_for that you can submit at the same time.
I have never created custom routes and actions or submitted 2 children forms in the same page.
Anyone know how I could do this ? Thanks
routes.rb
#this route shows the form
get 'create-players/:id', to 'game#new_players', as: :new_players
# this route recieves the form post submission
post 'create-players/:id', to 'game#create_players', as: :create_players
app/controllers/game_controller.rb:
def new_players
#game = Game.find(params[:id])
end
def create_players
#do whatever you want with the params passed from the form like
#allies = Ally.create(game_id: params[:id], name: params[:ally_fields][:name])
#enemies = Enemy.create(game_id: params[:id], name: params[:enemy_fields][:name])
#game = Game.find(params[:id])
end
app/views/game/new_players.html.erb:
<%= form_tag(create_players_paths, #game.id), method: 'POST') do %>
<% #...fields you have on models, perhaps %>
<% fields_for :ally_fields do |f|
<%= f.text_field :name, nil, placeholder: "Ally name", required: true
<% end % >
<% fields_for :enemy_fields do |f|
<%= f.text_field :name, nil, placeholder: "Enemy name", required: true
<% end % >
<%= submit_tag "create players", class: "submit" %>
<% end %>
app/views/game/create_players.html.erb:
<h1> Woah an allie and an enemy have been added to game <%= #game.id %></h1>
<p> Lets see some blood!</p>
Of course, you should enforce verifications on the input and before processing the post submission. Usually you'll want to use established relationships between objects, so that you can do on the view #model = Modelname.new then, form_for #object and have validations and error messages accessible in a much cleaner way.
Related
I have a form where users look for a particular bill by some attributes of that bill, namely the "Congress Number", "Bill Type", and "Bill Number", as in 114-H.R.-67 . I want to "show" the appropriate bill, but to do that I have get the appropriate bill model in a separate action which I've called "find_by_attributes". Inside this action I perform:
#bill = Bill.find_by( params ).first
which correctly acquires the appropriate bill's id.
Now I simply want to redirect to the "show" method of this bill, as in the url
".../bills/[#bill.id]"
As of right now, at the end of my "find_by_attributes" action I do
redirect_to bills_path(#bill)
which correctly loads the show.html.erb with #bill, but does not change the url (the url is still shows the "find_by_attributes" action followed by a long query-string, instead of the clean "/bills/[:bill_id]".
How can I restructure my code to achieve the neat redirect that I desire?
Full code below:
THE FORM
<%= form_tag("bills/find_or_create", :method => :get ) do |f| %>
<%# render 'shared/error_messages', object: f.object %>
<%= fields_for :bill do |ff| %>
<%= ff.label :congress, 'Congress (i.e. 114)' %>
<%= ff.number_field :congress, class: 'form-control' %>
<%= ff.select :bill_type, options_for_select(
[['House of Representatives', 'hr'],
['Senate', 's'],
['House Joint Resolution', 'hjres'],
['Senate Joint Resolution', 'sjres'],
['House Concurrent Resolution', 'hconres'],
['Senate Concurrent Resolution', 'sconres'],
['House Resolution', 'hres'],
['Senate Resolution', 'sres']]
)
%>
<%= ff.label :bill_number, 'Bill number (i.e. 67)' %>
<%= ff.number_field :bill_number, class: 'form-control' %>
<% end %>
<%= submit_tag "Submit", class: "btn btn-primary" %>
<% end %>
THE CONTROLLER ACTIONS
def find_by_attributes
#bill = Bill.where(bill_params).first_or_create(bill_attributes)
redirect_to bills_path(#bill)
end
def show
puts bill_params
if params[:bill]
#bill = Bill.where(bill_params).first_or_create do |bill|
bill.attributes = bill_attributes
end
else
#bill = Bill.find(params[:id])
end
#subjects = Subject.where("bill_id = ?", #bill[:id])
#bill_comments = Comment.where("target = ?", #bill[:id])
end
ROUTES FILE
...
resources :bills do
get :find_by_attributes
end
...
EDIT
I make use of the turbolinks gem in my rails application.
the thing I see here is that you are calling to
redirect_to bills_path(#bill)
that in theory is not the show path, you just need to remove the "s"
redirect_to bill_path(#bill)
and as a side comment, in this line, you don't need the first part, because find_b, finds the first record matching the specified conditions, you can remove that part.
#bill = Bill.find_by( params )
Let's say I have a bunch of cards listed on my wall show action. When you interact with a card (click it for example), I want to update that card's attributes.
I'm currently doing this by getting the card's attributes with Javascript, adding them to a card form and submitting the form remotely.
I have the card's ID, but how do I tell the form which card I want to update?
What should the form and controller update action look like?
This is what I have so far
Form
<%= form_for(#card, remote: true) do |f| %>
<%= f.text_field :list_id %>
<%= f.text_field :order %>
<% end %>
Controller
def update
#card = Card.find(params[:id])
if #card.update_attributes(shared_params)
redirect_to edit_card_path(#card, format: :html)
else
render :edit
end
end
You can use the same new template for edit too. The only requirement here is the object you wanted to edit.
So, first get you edit action ready in controller as
def edit
#card = Card.find(params[:id])
end
edit/new.html.erb
<%= form_for(#card, remote: true) do |f| %>
<%= f.text_field :list_id %>
<%= f.text_field :order %>
<% end %>
In the cards show page, add a link to the edit action as
<%= link_to "Edit", edit_card_path(card.id) %>
Forgive me. I am in Vegas and must just be dumb.
I have an Article model with many Attachments. And an Attachment model which belongs to an Article. So, if I create an article without an attachment, then I want to edit it and add an attachment I run into something interesting.
When my Article edit action looks like this:
def edit
end
When I update my article with an attachment, it doesn't work. But, when I update my article with an empty name and an empty content, I break the validations set up in my model as I'd expect. Here's the params hash when I do that.
Parameters: {"utf8"=>"✓","authenticity_token"=>"1X8Jr3Om2lrnhNEojTppKGRpRwF8/fidVHdC+H4UMPkAiF/oPF9yxB6j0jfL/I7VzUcDtTIh2iB+B7b19XN2Ug==", "article"=>{"name"=>"", "content"=>""}, "commit"=>"Update article", "business_id"=>"1", "id"=>"43"}
Now, when I change my edit action to this:
def edit
#article.attachments.build
end
When I update an article with an attachment, I get it and it works. BUT my validation is no longer checked. When I submit a ticket with an empty name and hash, it just returns back to the show page, as if updated, keeping the existing data.
I'm wondering why.
Here's my params hash when I do this with the edit action above:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"SQon3+gX/5vg9HKTUr/hWgRAagHIrA2PYexrq6Umasqc/XGYp+5XBRnTcYwUeQanrW4utYZwLzJLnJ+mLkEsYQ==", "commit"=>"Update article", "business_id"=>"1", "id"=>"43"}
Note, the params[:article] doesn't exist here as it does on the first, which is why, obviously, validations are skipped. My question, though, is why?
I wouldn't think this would be that hard, so I'm blaming Vegas :).
Update with views:
attachments/_form which exists if I call build on a new or edit for the article, but doesn't exist on edit unless build is in the edit, but I can click a JS button which links to the new action of the attachment in that case.
<%= f.simple_fields_for :attachments, child_index: index do |ff| %>
<%= ff.input :file, as: :file, label: "File ##{index += 1}" %>
<%= ff.input :file_cache, as: :hidden %>
<% end %>
Here's the article form:
<%= simple_form_for([#business, #article]) do |f| %>
<%= f.input :name %>
<%= f.input :content %>
<%= f.error :content_count, class: "alert-error" %>
<div id="attachments">
<h3>Attachments</h3>
<% index = 0 %>
<%= render partial: "attachments/form", locals: { f: f, index: 0 } %>
</div>
<p>
<% if !#article.persisted? %>
<%= link_to "Add another file", new_attachment_path, remote: true,
id: "add_file", data: { params: {index: #article.attachments.size} } %>
<% else %>
<%= link_to "Add another file", edit_attachment_path, remote: true,
id: "add_file", data: { params: {index: #article.attachments.size} } %>
<% end %>
</p>
<%= f.button :submit, class: "btn-primary" %>
I tried to add an if statement here in case I could send this request to different "actions" in the attachments controller, but it just replicates the issue, not corrects it, so you can ignore the if as I will remove it.
Here is the attachments controller though:
def new
#index = params[:index].to_i
#article = Article.new
#article.attachments.build
render layout: false
end
def edit
#index = params[:index].to_i
#article = Article.find(params[:id])
#article.attachments.build
render layout: false
end
One more edit adding the JS:
ready = ->
$("#add_file").on "ajax:success", (event, data) ->
$("#attachments").append data
$(this).data "params", { index: $("#attachments div.file").length }
When you said "When I update an article with an attachment" I assume you meant that you're clicking one of the "Add another file" buttons? As you mention in your new comment, there's JS code that creates the form field when you click the link.
Problem here is that actually it creates a whole <form>, and so when that's submitted it's coming through with just the file/attachment because it's not the same form as the one where your :name and :content etc. are.
You need to use your own JS there so that it creates just the fields (not a whole form) for your attachments.
I have a one to one relationship with Shares and Testimonials.
In Testimonial.rb:
belongs_to :share
In Share.rb:
has_one :testimonial
I want to add a form to the Shares page where I can create a testimonial which belongs to that specific share.
Inside the SharesController I set:
#testimonial = #share.build_testimonial
In the Shares view I have:
<%= form_for #testimonial do |f| %>
<%= f.text_area :message %>
<%= f.submit "Submit testimonial" %>
Is the above correct or do I have to add the share object to the view somehow?
What do I add to the create action in the Testimonials controller to create the testimonial and associate it with the #share object?
I have tried to send the share_id to the Testimonials controller from the view as an additional param and then used a "before" filter to find the share object but I don't think that's the right way to do it.
In the share.rb model, you'd want to add:
accepts_nested_attributes_for :testimonial
Since you are in the share view, I would think you'd have a construct in that view of:
<%= form_for #share do |f| %>
...
<% end %>
In that context, to use the testimonial fields:
<%= form_for #share do |f| %>
<%= fields_for #share.testimonial do |t| %>
<%= t.text_area :message %>
<% end %>
<% end %>
In a rails project I have two entities, Users and Institutions, they have a many-to-many relationship.
The views for them are set up to create new users and institutions but I want to have another view for linking the two.
In rails console all I have to do is
myuser.institutions << the_institution_i_just_created
The controller can do some of the work but how do I handle the submissions and the forms? I want to use a selection box so that the input is limited to the Institutions already in existence.
<select id="institution_selection" name="institution_sel">
<% selections = []
Institution.all.each do |institution|
pair = [institution.name, institution.id]
selections.concat([pair])
end
%>
<%= options_for_select(selections) %>
</select>
So the question in summary is how do I map this submission to an object so that in the controller I can do add it to the relation?
The solution was:
Alright, so this is the solution I came up with, I'm sure there is a better way to go about it and I'll continue to look into it but at least I got something close to what I was aiming for
def test
if !session[:user]
redirect_to users_path, notice: "Please login first"
end
if params[:institution]
#user = User.find(session[:user])
#institution = Institution.find(params[:institution][:id])
#user.institutions << #institution
redirect_to #user, notice: "Institution was successfully added "
end
end
and for the view
<%= form_tag("/users/test", :method => "post") do %>
<%= collection_select :institution, :id, Institution.all, :id, :name %>
<%= submit_tag("Search") %>
<% end %>
Use collection_select
<% from for #instancevar do |form| %>
<%= form.collection_select :institution_id, Institution.all, :id, :name %>
# Do other stuff....
<% end %>