Do calculation using radio_button variable to nested form controller - Rails 3 - ruby

I have a edit form which I have a radio_button that I would like to pass to a controller action and then use it to do a calculation. In the view I have:
<div class="field">
<%= radio_button_tag(:rating_select, "Up") %>
<%= label_tag(:rating_select, "Good.") %>
<%= radio_button_tag(:rating_select, "Down")%>
<%= label_tag(:rating_select, "Bad.")%>
</div>
In the controller I have:
def rating
#post = Post.find(params[:id])
.....
end
def update
#post = Post.find(params[:id])
##rating_select = params[:rating_select]
if #post.rating_select == "Up"
#post.score += 5
elsif #post.rating_select == "Down"
#post.score -= 5
end
......
end
Currently it is ignoring the if statement so the parameter isn't getting set properly. Ideally I would like to just use a temp variable from the view to use in the if statement to decide if I need to add or subtract in the update. But I also have a rating_select field in post if I need to use it also. Thanks.
UPDATE:
Thanks. That makes sense, I changed it to below but it still isn't incrementing or decrementing the score based on the radio box. So it seems it isn't getting the rating_select?:
def update
#post = Post.find(params[:id])
if params[:rating_select]=="Up"
#post.score += 5
elsif params[:rating_select]=="Down"
#post.score -= 5
end
respond_to do |format|
....
UPDATE2:
Finally figured it out, used another model Ratings to store association. I used the before_save in the Post model and it allowed me to do the calculation and save. What a headache.
before_save :set_rating
def set_rating
if self.rating.rating_select=="Up"
rating.score += 5
elsif self.rating.rating_select=="Down"
rating.score -= 5
end
end

Well, first off, in the code you're showing the post loaded in your update action is not receiving the params from your view.
Your code for an update action should typically look like this:
def update
#post = Post.find(params[:id])
if #post.update_attributes(params[:post])
... do stuff ...
else
render :edit, :alert => 'Unable to update post.'
end
end
Second, since you're using form_tag helper and not form_for, then you're not getting the params all setup for your model (ie. nested under params[:post]). So, in this case, your rating_select option is just a value by itself, which you can test for like this:
if params[:rating_select]=="Up"
...
else
...
end
The big thing to understand from your code is #post doesn't know anything about params[:rating_select], even if you used #post.update_attributes(params[:post]), because radio_button_tag as you have it set up is not building a hash of post attributes, it's just a standalone field.
I hope that makes sense, if you don't understand please leave comments and I'll try to explain more.

Related

rails buttons click counter

This is another I'm-totally-new-to-Ruby-please-have-mercy situation.
So i'm trying to figure out how to make a database of all my buttons to save the click count each time they're clicked. I started a new rails to try it out and generated a model Buttonand a controller buttons index
route.rbs
Rails.application.routes.draw do
resources :buttons
root 'buttons#index'
end
migration
class CreateButtons < ActiveRecord::Migration[5.0]
def change
create_table :buttons do |t|
t.integer :clicks
t.timestamps
end
end
end
buttons_controller
class ButtonsController < ApplicationController
def index
#button = Button.find(1)
end
def doit
#button = Button.find(1)
#newcount = #button.clicks + 1
Button.find(1).update_attributes(:clicks => #newcount)
end
end
Now.. i need to trigger the doit method.. is it possible to trigger a non CRUD operation ?
i tried this but it doesn't seem to work
index.html.erb
<h1>Hello, This is button and my click are :</h1>
<h1><%= #button.clicks %></h1>
<%= link_to 'click me', method: :doit %>
I know there's something I'm not getting here...
Ruby have been doing so much magic that I can't do a simple ruby method.. it have been really hard for me getting the part were methods are taking place without calling them by name..
Specially when I trigger a delete method and the destroy method is triggered by that.. I really need to get used to this too-much-magic coding
Several things to improve, I think. Please get back to me if something is not working (I did not run the code)
Make your index action list all the buttons
Controller:
def index
#buttons = Button.all
end
View:
<h1>These are all my buttons</h1>
<% #buttons.each do |button| %>
<%= link_to("Button #{button.id}", button_votes_path(button), method: :post) %>
<% end %>
It's common to have index show a list of resources.
Only create the routes you need, make increment a separate action
I'd chose to call it "vote". You could also call it "clicks" or "presses" or whatever.
resources :buttons, only: [:index] do
resources :votes, only: [:create]
end
Add the votes controller
class VotesController < ApplicationController
def create
button = Button.find(params[:id])
button.clicks += 1
button.save
redirect_to buttons_path
end
end
No error handling here. So this is just to get you started.
For the next steps I suggest you follow a tutorial or start with simpler stuff.

Rails 4 : Custom routes, multiple edit forms for a single model

I have a Rails 4 app, with a Thing model that have 3 attributes : attr_1, attr_2, attr_3.
I would like to have two edit forms :
the first one would update attr_1 and attr_2
the second one would only update attr_3
I have written four methods in my things_controller.rb :
def edit
#edit form for attr_1 & attr_2
end
def edit_attr_3
#edit form for attr_3 only
end
def update
#update attr_1 & attr_2
end
def update_attr_3
#update attr_3 only
end
And here's my routes.db
resources :things do
member do
get :edit_attr_3
put :update_attr_3
end
end
Now, GET to both edit views work (/things/:id/edit and /things/:id/edit_attr_3) but on submit, the thing#update form is called both times (thing#update_attr_3 is never called)
How can I proceed to get thing#edit_attr_3 action linked to thing#update_attr_3 please ?
EDIT :
Answer, thanks to Ross & Steve Klein :
In my views, I am using bootstrap_form_for. Usually the :url parameter is optional, as standard edit/update are linked by convention. In the case of custom edit or update actions, it is necessary to specify the update path.
<%= bootstrap_form_for #thing, url: update_attr_3_thing_path(#thing) do |f| %>
<% end %>
It's hard to say without seeing the code for your form... but if you are using form_for then the route it will map to the update action in both cases (with an object that is not a new object).
To make it work with your unique update action, you will have to specify the url that form_for should use. Something like:
<%= form_for #thing, url: things_update_attr_3_path(#thing) do |f| %>
# other form stuff .......
You can use bundle exec rake routes at the command prompt to see what your current routes are, so that you now what route helper to use with form for.

Rendering partial that belongs to another controller

I've got a menu controller, which is set as my root controller in routes.rb. In my menu view, i try and render the _lights.slim partial with = render :partial => 'lights/lights' but i get the following error: undefined method `lights' for nil:NilClass
MenuController:
class MenuController < ApplicationController
def index
end
end
Menu View (index.slim)
ul.tabs.vertical data-tab=""
li.tab-title.active
a href="#panel1a" Tab 1
.tabs-content.vertical
#panel1a.content.active
= render :partial => 'lights/lights'
LightsController
class LightsController < ApplicationController
before_action :discover_lights
include LIFX
#client = LIFX::Client.lan
#client.discover!
3.times do
#client.lights.refresh
sleep (0.5)
puts "Found #{#client.lights.count} with labels #{#client.lights}"
end
def index
end
def new
end
def light_toggle
light = #client.lights.with_label(params[:label])
light.on? ? light.turn_off : light.turn_on
redirect_to '/'
end
private
def discover_lights
#client = LIFX::Client.lan
#client.discover!
end
end
Lights View (_lights.slim)
h1.subheader LIFX Lights
table.light-table
thead
tr
th Light
th Status
th Power On/Off
th Brightness
tbody
-#client.lights.map do |c|
tr
th #{c.label}
th #{c.power}
th =link_to 'Toggle', light_path(:label => c.label)
th #{c.color.brightness.round(2) * 100}%
end
Routes.rb
root 'menu#index'
get '/lights', to: 'lights#index'
get '/lights/:label', to: 'lights#light_toggle', as: 'light'
I know this is a no brainer, but i'm stuck as to what to do here. I'm thinking it must be an issue with the way that when Menu#Index is called, I never knows about my LightsController, and so #client.blablabla will never make sense. But how will I make my app know about my LightsController when the view is loaded as a partial
Partials
You must appreciate that Partials are not controller-dependent (being stored in a controllers' view directory does not tie them for use with that controller)
This means if you have the functionality to support the partial in another controller, you should be able to use it in different parts of your app
--
Error
This leads us to the identification of the problem you're receiving.
It's not the calling of the partial which causes an issue - it's how you're referring to the code inside it:
undefined method `lights' for nil:NilClass
The error is clearly that you're trying to call the lights method on an object / variable which doesn't exist. This is defined inside the partial itself here:
#client.lights.map do |c|
Therefore, you need to be able to pass the correct data to the partial, enabling it to load the #client object without being dependent on the controller
--
Fix
To do this, you may wish to consider using partial locals -
<%= render partial: "lights/lights", locals: {client: #client} %>
This means that every time you call the partial, you'll have to pass the #client object into the client local var, thus allowing the partial to run controller-independently.
Here's how you'd handle it in the partial itself:
#app/views/lights/_lights.slim
- client.lights.map do |c|

undefined method `each' for nil:NilClass -- again-- i dont get it. Constantly getting this error

class ProfileController < ApplicationController
def show
#user = current_user
#first_name = #user.first_name
#last_name = #user.last_name
end
def settings
end
def pics
#photos = current_user.photos.all
end
end
in the view of _pics.html.erb, I have
<% #photos.each do |p| %>
<%= image_tag p.image(:medium) %>
<% end %>
If I change it to current_user.photos.each do |p|, it works, which is weird. I don't get an error from this code on my other computer.
In a comment you said, that you render the pics partial from your show view. Since the show view is rendered by the show action and the show action does not set the #photos variable, you can't use that variable. So to fix your problem, you'd need to set the variable in the show action.
You seem to think that rendering the pics partial will invoke the pics action, but that's not the case. An action will only be invoked if an URL is accessed that's mapped to that using the routing system. Rendering partials does not invoke any actions.
Also it should just be #photos = current_user.photos without the all.

Passing Form Params to Model in Rails3

I'm trying to pass some parameters (count) from a form to a model.
The model basically creates a user X times.
In our form, we have this:
= f.text_field :count
And I can see this is submitted properly in the dev. log:
user"=>{"count"=>"2"}
I've tried this in my controller:
#user = User.generate(params[:count])
Generate is then supposed to call this in my user model:
def self.generate(count=10)
count.times do
.....
end
I basically need the '10' replaced with the count from form.
How can I go about this?
-- UPDATE 1 --
I've edited as below but get had to change from count to usercount because I think that's reserved in rails..
I have this in my controller:
#user = User.generate(params[:user][:usercount])
This in my user.rb:
attr_accessor :usercount
def self.generate
usercount.times do
...
end
When I submit, I get this:
ArgumentError (wrong number of arguments (1 for 0)):
app/models/user.rb:22:in `generate'
app/controllers/users_controller.rb:38:in `new_users_create'
Really frustrating...
class User
attr_accessor :count
end
#user = User.generate(params[:user][:count])
should work fine.

Resources