Ruby on Rails 3: Toggle Boolean with Forms - ruby-on-rails

Users are able to send each other messages on my Ruby app. The table is as followed:
t.string "content"
t.integer "from_id"
t.integer "reply_to_id"
t.boolean "read", :default => false
I have recently added the boolean, :read, and I have the form linked to messages in their inbox. When they click "Mark Read" (the link provided via the form) I want it to toggle :read => true.
I am currently unable to accomplish this. This is my current setup.
_mark_read.html.erb
<%= form_for(:message, :mark_read => {read: true}) do |f| %>
<div><%= f.hidden_field :read %></div>
<%= f.submit "Mark Read", class: "btn-link" %>
<% end %>
Class MessagesController < ApplicationController
def mark_read
#message = current_user.messages.build
#message.toggle!(:read)
end
config/routes.rb
match '/mark_read' => 'messages#mark_read', :via => :post, :as => :mark_read
When I click "Mark Read", here is my debug info:
--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: ✓
authenticity_token: ---
message: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
read: 'false'
commit: Mark Read
controller: static_pages
action: connect
I can see it is not even using my controller... and even so; I don't think I have it set up correctly.
Any advise as to how this should be set up would be kindly appreciated.

Believe it or not.. I didn't even need a model, nor controller :D As I said it is rendered within a paginated set. This paginated set is defined at #inbox_items identified as inbox_item.id.
Here is the form that works without any need of a model or controller. It is simply defined in config/routes.rb as:
match '/mark_read' => 'messages#mark_read', :via => :post
The form:
<ul class="share-actions" id="mark_read<%= inbox_item.id %>">
<%= form_for :mark_read do |f| %>
<%= f.check_box inbox_item.toggle!(:read) %>
<%= f.submit "Mark Read", class: "btn btn-link" %>
<% end %>
</ul>
Ammusing, huh? :D
More information in-case you are curious. The base Class of rendered #inbox_items, is Class Message. Messages define all of user's private posts. In the User class I begin to set up how #inbox_items will be defined:
Class User
def inbox
Message.from_users_inbox(self)
end
Then I build the rest:
Class Message
def self.from_users_inbox(user)
"SELECT best_friend_id FROM friendships WHERE new_friend_id = :user_id"
where("user_id = :user_id OR reply_to_id = :user_id", user_id: user.id)
end
MemberpagesController
def inbox
#message = current_user.messages.build
#inbox_items = current_user.inbox.paginate(page: params[:page])
end
feeds/_inbox.html.erb
<% if #inbox_items.any? %>
<%= render: 'feeds/inbox_item', collection: #inbox_items %>
<%= will_paginate #inbox_items %>
<% end %>
And finally:
feeds/_inbox_item.html.erb
<div id="<%= inbox_item.user.name %>_<%= inbox_item.id %>">
...
<ul class="share-actions" id="mark_read<%= inbox_item.id %>">
<%= form_for :mark_read do |f| %>
<%= f.check_box inbox_item.toggle!(:read) %>
<%= f.submit "Mark Read", class: "btn btn-link" %>
<% end %>
</ul>
...
And that did it! :)

Related

rails - multiple paths for a search form

I'm implementing the website. I got a problem for a search form. I upload my code, and what i want to ask is how to set the search 'path' through 'index' and 'historical' on homes_controller
Below, my code:
app/controllers/homes_controller
def index
#homes = Home.where(:category => 1).reverse
end
def historical
#homes = Home.where(:category => 2).reverse
end
app/views/layouts/application.html.erb
Below, this code is temporary code for now. I should change it.
<%= form_tag(homes_path, :method => 'get', id: "search-form" do %>
<%= text_field_tag :search, params[:search], placeholder: "검색" %>
<%= submit_tag "검색", :name => nil %>
<% end %>
Am not sure what you are supposed to do here
But as per the question - I can give a solution to your problem
Keep an instance variable in your controller actions - like this
app/controllers/homes_controller
def index
#homes = Home.where(:category => 1).reverse
#search_path = "path you want to give"
end
def historical
#homes = Home.where(:category => 2).reverse
#search_path = "path you want to give"
end
and in your layout you can use it like this
app/views/layouts/application.html.erb
<%= #search_path.present? %>
<%= form_tag(#search_path, :method => 'get', id: "search-form" do %>
<%= text_field_tag :search, params[:search], placeholder: "검색" %>
<%= submit_tag "검색", :name => nil %>
<% end %>
<% end %>

Dynamic routing base on clicked bottoms

please am stocked trying to create a way for an admin to preview a file before creating users from the file("an xls file"), the problem am faced with is not knowing how to dynamically change the route base on the button the admin clicked, the buttons are supposed to either go to preview the file or create the users from the file.
<%= form_for :create_student, url:"/create_from_file", remote:true, html:{id:"create_student_from_file"} do|f| %>
<div id="student-fields0" class="fields_div">
<%= f.label "Upload file"%>
<%= f.file_field :Upload_file %>
<%= f.submit :create, id: 'create_student' %>
<div id="preview_student" class="button">preview</div>
</div>
<% end %>
I would solve this that way, for example:
Controller part
class YourContoller < ApplicationController
# POST /create_from_file
def create_from_file
# Initialize user or something
user = User.new(params)
if params[:preview]
return redirect_to(:preview_from_file, user: user)
end
# Create new user here
end
# GET /preview_from_file
# Add another view for preview page
def preview_from_file
#user = params[:user]
end
end
View part
<%= form_for :create_student, url:"/create_from_file", remote:true, html:{id:"create_student_from_file"} do|f| %>
<div id="student-fields0" class="fields_div">
<%= f.label "Upload file"%>
<%= f.file_field :Upload_file %>
<%= f.submit :create, id: 'create_student' %>
// This is what changed compared to your current view
<%= submit_tag 'preview', name: 'preview', value: 'true', class: 'button' %>
</div>
<% end %>

How to do the calculation without any models in Rails?

I need to get an integer(#integer) from the form in my root_path, do multiplication (#integer*45) and display the result on the same page. How can I do it without any models in my application?
Please, share your best practice. Thank you!
I was trying to do next:
CalculatorsController
def calculation
#integer = params[:integer]
#result = #integer*45
end
def result
end
root.rb
root :to => 'calculators#result'
resources :calculators, :collection=>{:result => :get, :calculation => :post}
calculators/result.html.erb
<% form_tag root_path, :html => {:method => :post} do %>
<%= label_tag 'integer' %>
<%= text_field_tag :integer %>
<div><%= submit_tag 'OK' %></div>
<% end %>
I'll do it with ajax, so there is no need for page refresh:
First, update the routes, for your example you only need two routes, one get (or root) and one post.
routes.rb:
Rails.application.routes.draw do
root 'calculators#result'
post 'calculators/calculation'
end
Next, update your view:
Change the url in your form_tag where the data will be sent (to calculation action instead of result).
Add remote: true option to enable ajax.
Add a tag where you will display your result.
result.html.erb:
<% form_tag calculators_calculation_url, remote: true do %>
<%= label_tag 'integer' %>
<%= text_field_tag :integer %>
<div><%= submit_tag 'OK' %></div>
<% end %>
<div id="total"></div>
And create a view for calculation action, but since you are using ajax, you will create it as js.erb and include the required javascript (or jQuery) to update your view (i'm using jQuery in the example).
calculation.js.erb:
$('#total').html('<%= #result %>')
Now when you click submit, your form will be sent to calculation action and will update the div with #result.
Just add the field to your form...
<% form_tag root_path, :html => {:method => :post} do %>
<%= label_tag 'integer' %>
<%= text_field_tag(:integer, #integer) %>
<% if #result.present? %>
<br>
Result is: <%= #result %>
<br/>
<% end %>
<div><%= submit_tag 'OK' %></div>
<% end %>
And then render result in your calculate...
def calculation
#integer = params[:integer].to_i
#result = #integer*45
render :result
end
Your result view (result.html.erb) is getting its data from the result method, not calculation. Update your controller as follows:
def calculation
#integer = params[:integer]
end
def result
#result = #integer*45
end
You then need a tag to display your result in the view, something like:
<p> <%= #result %> </p>

How to make a link_to that redirects and submits a form

I have a modal that will serve as a disclaimer in my app and I need the link at the bottom of the modal that says "agree & continue" to toggle a boolean and input the time that the boolean was toggled. I have created the button as a form with hidden links but I cant seem to see how to make it submit the form AND redirect to the path i specify. Here is my link_to code now.
<% if current_user.user_record.blank? %>
<%= form_for :user do |f| %>
<% f.hidden_field :disclosure_acceptance, :value => true %>
<% f.hidden_field :disclosure_date, :value => Time.now %>
<%= link_to("Agree & Continue", user_steps_path(current_user), class: "btn btn-primary") %>
<% end %>
<% end %>
First, create a new method in your user_records_controller or at whichever controller action the form is displayed at:
def new
#user_record = current_user.build_user_record
end
Put this in your view:
<% if current_user.user_record.blank? %>
<%= form_for #user_record do |f| %>
<%= f.hidden_field :disclosure_acceptance, :value => true %>
<%= f.hidden_field :disclosure_date, :value => Time.now %>
<%=f.submit "Agree & Continue", class: "btn btn-primary") %>
<% end %>
<% end %>
Make a create action for the user_record that looks like this:
def create
#user_record = current_user.build_user_record(permitted_params)
if #user_record.save
redirect_to user_steps_path(current_user)
else
render :new
end
end
private
def permitted_params
params.require(:user_record).permit(:disclosure_acceptance , :disclosure_date) #etc
end
UPDATE
If you directly want to jump to the 'create' action, you can make your configuration like this:
Add a custom action to your routes:
post 'rate/:article_id' => 'user_records#create' :as => :create_user_record
#or whichever controller/action you wish
You should update the route on your form:
= form_tag create_user_record_path, :method=>'post' do
#etc
In order to create a user_record from the controller, you need to change things a little bit:
def create
current_user.user_record.create(:user_id => current_user.id, :disclosure_acceptance => params[:disclosure_acceptance] , :disclosure_date => params[:disclosure_date])
if current_user.user_record.save
#etc
end

Rails 4 - Toggle Boolean to false on click

I am trying to use Rails 4 to build an app.
The app has 3 models - one for Project, one for Scope and one for Finalise.
Finalise belongs to scope. Scope belongs to Project. Project accepts nested attributes for Scope (and Finalise) and Scope accepts nested attributes for Finalise.
In my finalise model, I have a boolean attribute for :draft. If draft is true, then I want to include a link on the project show page to toggle the :draft to false when the draft is complete.
A SO member has given me some suggestions in the attached (which I have tried to follow, but have not served to toggle the boolean attribute).
In my projects controller, I have:
def new
#authorise #project
#project = Project.new
#project.scope = Scope.new
#project.scope.finalise = Finalise.new
end
In my scopes controller, I have;
def new
#scope = Scope.new
#scope.finalises.build
end
In my finalises controller, I have a method (which was suggested by another SO user):
def toggle_draft
#finalise = Finalise.find(params[:id])
#finalise.draft = true
#finalise.save
redirect_to project_path(#project)
end
The finalise route has:
resources :finalises do
patch '/toggle-draft', to: 'finalises#toggle_draft', as: 'toggle_draft'
end
The finalise partial show (which is incorporated in the project show) has:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #finalise.id), :remote => true, method: :patch %></div>
<% end %>
When I try this I get an error that says:
undefined method `id' for nil:NilClass
Gabriel (below) has suggested that I might need to link through the associations (so #project.scope.finalise.id). I have tried that formulation and #project.scope.finalise_id. Neither of these work either.
When I try it as:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #project.scope.finalise.id), :remote => true, method: :patch %></div>
<% end %>
I get an error that says:
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>1} missing required keys: [:finalise_id]
When I try:
I get an error that says:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
finalise_toggle_draft_path(:id => #project.scope.finalise.id), :action => 'toggle-draft', :remote => true, method: :patch %></div>
<% end %>
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>1} missing required keys: [:finalise_id]
When I try:
I get this error:
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft',
controller: "finalises", action: "toggle_draft",
finalise_id: #finalise_id,
:remote => true,
method: :patch %>
</div>
<% end %>
No route matches {:action=>"toggle_draft", :controller=>"finalises", :id=>"53", :finalise_id=>nil, :method=>:patch}
Thank you
in projects_controller
def show
#project = Project.find(params[:id])
end
in the projects show view
<%= link_to 'Finalise draft', finalise_toggle_draft_path(#project.scope.finalise.id), method: :patch
You should be able to use the named route and pass the finalise id which you can get from #project. You'll have to be careful how you get the finalise model in the finalises#toggle_draft method, check how your params are named, probably finalise_id, and not id. It would be good to read up on nesting resources and how to pass variables between controllers.
This is what ended up working (using Margo's guidance):
finalises partial:
<div class="finalise">
<%= link_to 'Finalise draft', finalise_toggle_draft_path(projectid: #project.id, id: #project.scope.finalise.id, finalise_id: #project.scope.finalise.id), method: :patch %>
</div>
Finalises_controller
def toggle_draft
#finalise = Finalise.find(params[:id])
#finalise.draft = false
#finalise.finalised = Time.now
#finalise.save
redirect_to project_path(Project.find(params[:projectid]))
#finalise_idis not defined... You can gat the id through the relation #project.scope.finalise.id
<% if #project.scope.finalise.draft == true %>
<div class="finalise"> <%= link_to 'Finalise this draft', finalise_toggle_draft_path(id: #project.scope.finalise.id), method: :patch %></div>
<% end %>

Resources